first commit

This commit is contained in:
2025-11-28 10:08:12 +08:00
commit 09a14bf0a3
1088 changed files with 145132 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
<?php
namespace lib;
class AliyunCertify {
private $AccessKeyId;
private $AccessKeySecret;
private $Endpoint = 'saf.cn-shanghai.aliyuncs.com'; //API接入域名
private $Version = '2017-03-31'; //API版本号
private $SceneId;
function __construct($AccessKeyId, $AccessKeySecret, $SceneId){
$this->AccessKeyId = $AccessKeyId;
$this->AccessKeySecret = $AccessKeySecret;
$this->SceneId = $SceneId;
}
//身份认证初始化服务
public function initialize($outer_order_no, $cert_name, $cert_no, $return_url) {
$params = [
'method' => 'init',
'sceneId' => $this->SceneId,
'outerOrderNo' => $outer_order_no,
'bizCode' => 'FACE_SDK',
'identityType' => 'CERT_INFO',
'certType' => 'IDENTITY_CARD',
'certNo' => $cert_no,
'certName' => $cert_name,
'returnUrl' => $return_url
];
$ServiceParameters = json_encode($params);
return $this->ExecuteRequest($ServiceParameters);
}
//身份认证记录查询
public function query($certify_id) {
$params = [
'method' => 'query',
'certifyId' => $certify_id,
'sceneId' => $this->SceneId
];
$ServiceParameters = json_encode($params);
return $this->ExecuteRequest($ServiceParameters);
}
//执行请求
private function ExecuteRequest($ServiceParameters){
$param = ['Action' => 'ExecuteRequest', 'Service' => 'fin_face_verify', 'ServiceParameters' => $ServiceParameters];
return $this->request($param, true);
}
//签名方法
private function aliyunSignature($parameters, $accessKeySecret, $method)
{
ksort($parameters);
$canonicalizedQueryString = '';
foreach ($parameters as $key => $value) {
if($value === null) continue;
$canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
}
$stringToSign = $method . '&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
$signature = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret . "&", true));
return $signature;
}
private function percentEncode($str)
{
$search = ['+', '*', '%7E'];
$replace = ['%20', '%2A', '~'];
return str_replace($search, $replace, urlencode($str));
}
//请求方法(当需要返回列表等数据时,returnData=true
private function request($param, $returnData=false){
if(empty($this->AccessKeyId)||empty($this->AccessKeySecret))return false;
$url='https://'.$this->Endpoint.'/';
$data=array(
'Format' => 'JSON',
'Version' => $this->Version,
'AccessKeyId' => $this->AccessKeyId,
'SignatureMethod' => 'HMAC-SHA1',
'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
'SignatureVersion' => '1.0',
'SignatureNonce' => $this->random(8));
$data=array_merge($data, $param);
$data['Signature'] = $this->aliyunSignature($data, $this->AccessKeySecret, 'POST');
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
$json=curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$arr=json_decode($json,true);
if($returnData==true){
return $arr;
}else{
if($httpCode==200){
return true;
}else{
return $arr['Message'];
}
}
}
private function random($length, $numeric = 0) {
$seed = base_convert(md5(microtime().$_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
$seed = $numeric ? (str_replace('0', '', $seed).'012340567890') : ($seed.'zZ'.strtoupper($seed));
$hash = '';
$max = strlen($seed) - 1;
for($i = 0; $i < $length; $i++) {
$hash .= $seed[mt_rand(0, $max)];
}
return $hash;
}
}
+127
View File
@@ -0,0 +1,127 @@
<?php
namespace lib;
use Exception;
class AliyunRecognize
{
private $AccessKeyId;
private $AccessKeySecret;
private $Endpoint = 'ocr-api.cn-hangzhou.aliyuncs.com'; //API接入域名
private $Version = '2021-07-07'; //API版本号
function __construct($AccessKeyId, $AccessKeySecret){
$this->AccessKeyId = $AccessKeyId;
$this->AccessKeySecret = $AccessKeySecret;
}
//身份证识别
public function RecognizeIdcard($file_path){
$arr = $this->request(__FUNCTION__, file_get_contents($file_path), true);
return json_decode($arr['Data'],true);
}
//护照识别
public function RecognizePassport($file_path){
$arr = $this->request(__FUNCTION__, file_get_contents($file_path), true);
return json_decode($arr['Data'],true);
}
//银行卡识别
public function RecognizeBankCard($file_path){
$arr = $this->request(__FUNCTION__, file_get_contents($file_path), true);
return json_decode($arr['Data'],true);
}
//营业执照识别
public function RecognizeBusinessLicense($file_path){
$arr = $this->request(__FUNCTION__, file_get_contents($file_path), true);
return json_decode($arr['Data'],true);
}
//银行开户许可证识别
public function RecognizeBankAccountLicense($file_path){
$arr = $this->request(__FUNCTION__, file_get_contents($file_path), true);
return json_decode($arr['Data'],true);
}
//签名方法
private function aliyunSignature($parameters, $accessKeySecret, $method)
{
ksort($parameters);
$canonicalizedQueryString = '';
foreach ($parameters as $key => $value) {
if($value === null || $value instanceof \CURLFile) continue;
$canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
}
$stringToSign = $method . '&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
$signature = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret . "&", true));
return $signature;
}
private function percentEncode($str)
{
$search = ['+', '*', '%7E'];
$replace = ['%20', '%2A', '~'];
return str_replace($search, $replace, urlencode($str));
}
//请求方法(当需要返回列表等数据时,returnData=true
private function request($action, $file = null, $returnData=false){
if(empty($this->AccessKeyId)||empty($this->AccessKeySecret))return false;
$url='https://'.$this->Endpoint.'/';
$data=array(
'Action' => $action,
'Format' => 'JSON',
'Version' => $this->Version,
'AccessKeyId' => $this->AccessKeyId,
'SignatureMethod' => 'HMAC-SHA1',
'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
'SignatureVersion' => '1.0',
'SignatureNonce' => $this->random(8));
$data['Signature'] = $this->aliyunSignature($data, $this->AccessKeySecret, 'POST');
$url.='?'.http_build_query($data);
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
if($file !== null){
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/octet-stream']);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $file);
}
$json=curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($httpCode>=200 && $httpCode<300){
if($returnData==true){
$arr = json_decode($json,true);
if(!$arr) throw new Exception('无法解析返回数据');
return $arr;
}else{
return true;
}
}else{
$arr=json_decode($json,true);
if(isset($arr['Code']) && isset($arr['Message'])){
if(strpos($arr['Message'],' server string to sign is:')!==false){
$arr['Message'] = substr($arr['Message'],0,strpos($arr['Message'],' server string to sign is:')-1);
}
throw new Exception('['.$arr['Code'].'] '.$arr['Message']);
}else{
throw new Exception('无法解析返回数据');
}
}
}
private function random($length, $numeric = 0) {
$seed = base_convert(md5(microtime().$_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
$seed = $numeric ? (str_replace('0', '', $seed).'012340567890') : ($seed.'zZ'.strtoupper($seed));
$hash = '';
$max = strlen($seed) - 1;
for($i = 0; $i < $length; $i++) {
$hash .= $seed[mt_rand(0, $max)];
}
return $hash;
}
}
+77
View File
@@ -0,0 +1,77 @@
<?php
namespace lib;
use Exception;
class ApiHelper
{
//无需签名验证的接口
private static $exclude_list = [
'pay/submit',
'pay/create',
'complain/image'
];
public static function load_api($s){
if(preg_match('/^(.[a-zA-Z0-9\_]+)\/(.[a-zA-Z0-9\_]+)$/',$s, $matchs)){
$class = $matchs[1];
$func = $matchs[2];
$classname = '\\lib\\api\\'.ucfirst($class).'';
if (class_exists($classname) && method_exists($classname, $func)) {
try{
if(in_array($class.'/'.$func, self::$exclude_list)){
$classname::$func();
}else{
self::verify();
$result = $classname::$func();
$result['timestamp'] = time().'';
$result['sign_type'] = 'RSA';
$result['sign'] = \lib\Payment::makeSign($result, null);
echojson($result);
}
}catch(Exception $e){
$code = $e->getCode();
echojsonmsg($e->getMessage(), $code != 0 ? $code : -1);
}
}else{
echojsonmsg('接口方法不存在', -5);
}
}else{
echojsonmsg('URL Error!', -5);
}
}
private static function verify(){
global $DB, $conf, $userrow, $queryArr;
if(isset($_POST['pid'])){
$queryArr=$_POST;
}else{
throw new Exception('未传入任何参数', -4);
}
$pid=intval($queryArr['pid']);
if(empty($pid))throw new Exception('商户ID不能为空');
$userrow=$DB->getRow("SELECT `uid`,`gid`,`key`,`money`,`channelinfo`,`keytype`,`publickey`,`status`,`pay`,`settle`,`refund`,`transfer` FROM `pre_user` WHERE `uid`='{$pid}' LIMIT 1");
if(!$userrow)throw new Exception('商户不存在!');
if($userrow['status']==0)throw new Exception('商户已被封禁');
try{
self::api_verify($userrow, $queryArr);
}catch(Exception $e){
throw new Exception($e->getMessage(), -3);
}
}
//API签名校验
static public function api_verify($userrow, $queryArr, $forceRsa = false){
if($forceRsa && $queryArr['sign_type'] != 'RSA')throw new Exception('该接口只能使用RSA签名类型');
if($userrow['keytype'] == 1 && $queryArr['sign_type'] != 'RSA')throw new Exception('该商户只能使用RSA签名类型');
if(defined('API_INIT') || $forceRsa){
if(empty($queryArr['timestamp']))throw new Exception('时间戳(timestamp)字段不能为空');
if(abs(time() - $queryArr['timestamp']) > 300)throw new Exception('时间戳字段不正确,请检查服务器时间');
}
$sign_type = $queryArr['sign_type'] ? $queryArr['sign_type'] : 'MD5';
if(!\lib\Payment::verifySign($queryArr, $userrow['key'], $userrow['publickey']))throw new Exception($sign_type.'签名校验失败');
}
}
+52
View File
@@ -0,0 +1,52 @@
<?php
namespace lib;
class Cache {
public function get($key) {
global $_CACHE;
return $_CACHE[$key];
}
public function read($key = 'config') {
global $DB;
$value = $DB->getColumn("SELECT v FROM pre_cache WHERE k=:key LIMIT 1", [':key'=>$key]);
return $value;
}
public function save($key ,$value, $expire=0) {
if (is_array($value)) $value = serialize($value);
global $DB;
if($expire) $expire = time() + $expire;
return $DB->exec("REPLACE INTO pre_cache VALUES (:key, :value, :expire)", [':key'=>$key, ':value'=>$value, ':expire'=>$expire]);
}
public function pre_fetch(){
global $_CACHE;
$_CACHE=array();
$cache = $this->read('config');
$_CACHE = @unserialize($cache);
if(empty($_CACHE['version']))$_CACHE = $this->update();
return $_CACHE;
}
public function update() {
global $DB;
$cache = array();
$result = $DB->getAll("SELECT * FROM pre_config");
foreach($result as $row){
$cache[ $row['k'] ] = $row['v'];
}
$this->save('config', $cache);
return $cache;
}
public function clear($key = 'config') {
global $DB;
return $DB->exec("UPDATE pre_cache SET v='' WHERE k=:key", [':key'=>$key]);
}
public function delete($key) {
global $DB;
return $DB->exec("DELETE FROM pre_cache WHERE k=:key", [':key'=>$key]);
}
public function clean() {
global $DB;
$DB->exec("DELETE FROM pre_cache WHERE expire>0 AND expire<'".time()."'");
//$DB->exec("OPTIMIZE TABLE pre_cache");
return true;
}
}
+341
View File
@@ -0,0 +1,341 @@
<?php
namespace lib;
class Channel {
static public function get($id, $channelinfo=null){
global $DB;
$value=$DB->getRow("SELECT * FROM pre_channel WHERE id='$id' LIMIT 1");
if(!$value) return null;
$channel = ['id'=>$value['id'], 'name'=>$value['name'], 'mode'=>$value['mode'], 'type'=>$value['type'], 'plugin'=>$value['plugin'], 'apptype'=>$value['apptype'], 'appwxmp'=>$value['appwxmp'], 'appwxa'=>$value['appwxa'], 'costrate'=>$value['costrate'], 'daytop'=>$value['daytop']];
$config = json_decode($value['config'], true);
if(!empty($channelinfo) && !empty($config)){
$arr = json_decode($channelinfo, true);
foreach($config as $configkey => $configrow){
if($configrow && substr($configrow, 0, 1) == '['){
$key = substr($configrow,1,-1);
$config[$configkey] = $arr[$key];
}
}
}
if(!empty($config)){
$channel = array_merge($channel, $config);
}
return $channel;
}
static public function getSub($id){
global $DB;
$value=$DB->getRow("SELECT A.*,B.info,B.id subid FROM pre_subchannel B INNER JOIN pre_channel A ON B.channel=A.id WHERE B.id='$id'");
if(!$value) return null;
$channel = ['id'=>$value['id'], 'subid'=>$value['subid'], 'name'=>$value['name'], 'mode'=>$value['mode'], 'type'=>$value['type'], 'plugin'=>$value['plugin'], 'apptype'=>$value['apptype'], 'appwxmp'=>$value['appwxmp'], 'appwxa'=>$value['appwxa'], 'costrate'=>$value['costrate'], 'daytop'=>$value['daytop']];
$config = json_decode($value['config'], true);
if(!empty($value['info']) && !empty($config)){
$arr = json_decode($value['info'], true);
foreach($config as $configkey => $configrow){
if($configrow && substr($configrow, 0, 1) == '['){
$key = substr($configrow,1,-1);
$config[$configkey] = $arr[$key];
}
}
if(isset($arr['apptype']) && !empty($arr['apptype'])){
$channel['apptype'] = $arr['apptype'];
}
if(isset($arr['appwxmp']) && $arr['appwxmp']>0){
$channel['appwxmp'] = $arr['appwxmp'];
$channel['subappwxmp'] = 1;
}
if(isset($arr['appwxa']) && $arr['appwxa']>0){
$channel['appwxa'] = $arr['appwxa'];
$channel['subappwxa'] = 1;
}
}
if(!empty($config)){
$channel = array_merge($channel, $config);
}
return $channel;
}
static public function getGroup($gid){
global $DB;
$group=$DB->getRow("SELECT * FROM pre_group WHERE gid='{$gid}' LIMIT 1");
if(!$group)$group=$DB->getRow("SELECT * FROM pre_group WHERE gid=0 LIMIT 1");
$info = json_decode($group['info'],true);
$rows = $DB->getAll("SELECT * FROM pre_type WHERE status=1 ORDER BY id ASC");
$paytype = [];
foreach($rows as $row){
$paytype[$row['id']] = $row['name'];
}
$subchannel_type = [];
foreach($info as $id=>$row){
if(!isset($paytype[$id]))continue;
if($row['channel'] == -2){
$subchannel_type[] = $paytype[$id];
}
}
$group['subchannel_type'] = $subchannel_type;
return $group;
}
static public function info($id, $gid = 0){
global $DB;
$value=$DB->getRow("SELECT id,plugin,type,rate,apptype,mode,paymin,paymax FROM pre_channel WHERE id='$id' LIMIT 1");
$money_rate = $value['rate'];
if($gid>0)$groupinfo=$DB->getColumn("SELECT info FROM pre_group WHERE gid='$gid' LIMIT 1");
if(!$groupinfo)$groupinfo=$DB->getColumn("SELECT info FROM pre_group WHERE gid=0 LIMIT 1");
if($groupinfo){
$info = json_decode($groupinfo,true);
$groupinfo = $info[$value['type']];
if(is_array($groupinfo) && !empty($groupinfo['rate'])){
$money_rate = $groupinfo['rate'];
}
}
return ['typeid'=>$value['type'], 'plugin'=>$value['plugin'], 'channel'=>$value['id'], 'rate'=>$money_rate, 'apptype'=>$value['apptype'], 'mode'=>$value['mode'], 'paymin'=>$value['paymin'], 'paymax'=>$value['paymax']];
}
static public function getWeixin($id){
global $DB;
$value=$DB->getRow("SELECT * FROM pre_weixin WHERE id='$id' LIMIT 1");
return $value;
}
// 支付提交处理(输入支付方式名称)
static public function submit($type, $uid=0, $gid=0, $money=0, $device=null){
global $DB;
if($device == 'mobile' || $device == 'qq' || $device == 'wechat' || $device == 'alipay' || checkmobile()==true){
$sqls = " AND (device=0 OR device=2)";
}else{
$sqls = " AND (device=0 OR device=1)";
}
$paytype=$DB->getRow("SELECT id,name,status FROM pre_type WHERE name=:type{$sqls} LIMIT 1", [':type'=>$type]);
if(!$paytype || $paytype['status']==0)sysmsg('支付方式(type)不存在');
$typeid = $paytype['id'];
$typename = $paytype['name'];
return self::getSubmitInfo($typeid, $typename, $uid, $gid, $money);
}
// 支付提交处理2(输入支付方式ID)
static public function submit2($typeid, $uid=0, $gid=0, $money=0){
global $DB;
$paytype=$DB->getRow("SELECT id,name,status FROM pre_type WHERE id='$typeid' LIMIT 1");
if(!$paytype || $paytype['status']==0)sysmsg('支付方式(type)不存在');
$typename = $paytype['name'];
return self::getSubmitInfo($typeid, $typename, $uid, $gid, $money);
}
//获取通道、插件、费率信息
static public function getSubmitInfo($typeid, $typename, $uid, $gid, $money){
global $DB;
if($gid>0)$groupinfo=$DB->getColumn("SELECT info FROM pre_group WHERE gid='$gid' LIMIT 1");
if(!$groupinfo)$groupinfo=$DB->getColumn("SELECT info FROM pre_group WHERE gid=0 LIMIT 1");
if($groupinfo){
$info = json_decode($groupinfo,true);
$groupinfo = $info[$typeid];
if(is_array($groupinfo)){
$channel = $groupinfo['channel'];
$money_rate = $groupinfo['rate'];
}
else{
$channel = -1;
$money_rate = null;
}
if($channel==0){ //当前商户关闭该通道
return false;
}
elseif($channel==-1){ //随机可用通道
$rows=$DB->getAll("SELECT id,plugin,status,rate,apptype,mode,paymin,paymax FROM pre_channel WHERE type='$typeid' AND status=1 AND daystatus=0");
if(count($rows)>0){
$newrows = [];
foreach($rows as $row){
if($money>0 && !empty($row['paymin']) && $row['paymin']>0 && $money<$row['paymin'])continue;
if($money>0 && !empty($row['paymax']) && $row['paymax']>0 && $money>$row['paymax'])continue;
$newrows[] = $row;
}
if(count($newrows)>0){
$row = $newrows[array_rand($newrows)];
}else{
$row = $rows[array_rand($rows)];
}
if(empty($money_rate))$money_rate = $row['rate'];
return ['typeid'=>$typeid, 'typename'=>$typename, 'plugin'=>$row['plugin'], 'channel'=>$row['id'], 'subchannel'=>0, 'rate'=>$money_rate, 'apptype'=>$row['apptype'], 'mode'=>$row['mode'], 'paymin'=>$row['paymin'], 'paymax'=>$row['paymax']];
}
}
elseif($channel==-2){ //用户自定义子通道
$rows=$DB->getAll("SELECT A.id,plugin,A.status,rate,apptype,mode,paymin,paymax,B.id subid FROM pre_subchannel B INNER JOIN pre_channel A ON B.channel=A.id WHERE B.uid='$uid' AND A.type='$typeid' AND A.status=1 AND B.status=1 AND daystatus=0 ORDER BY B.usetime ASC");
if(count($rows)>0){
$newrows = [];
foreach($rows as $row){
if($money>0 && !empty($row['paymin']) && $row['paymin']>0 && $money<$row['paymin'])continue;
if($money>0 && !empty($row['paymax']) && $row['paymax']>0 && $money>$row['paymax'])continue;
$newrows[] = $row;
}
if(count($newrows)>0){
$row = $newrows[0];
}else{
$row = $rows[0];
}
if(empty($money_rate))$money_rate = $row['rate'];
$DB->exec("UPDATE pre_subchannel SET usetime=NOW() WHERE id='{$row['subid']}'");
return ['typeid'=>$typeid, 'typename'=>$typename, 'plugin'=>$row['plugin'], 'channel'=>$row['id'], 'subchannel'=>$row['subid'], 'rate'=>$money_rate, 'apptype'=>$row['apptype'], 'mode'=>$row['mode'], 'paymin'=>$row['paymin'], 'paymax'=>$row['paymax']];
}
}
else{
if($groupinfo['type']=='roll'){ //解析轮询组
$channel = self::getChannelFromRoll($channel, $money);
if(!$channel || $channel==0){ //当前轮询组未开启
return false;
}
}
//获取轮询组对应通道
$row=$DB->getRow("SELECT plugin,status,rate,apptype,mode,paymin,paymax FROM pre_channel WHERE id='$channel' LIMIT 1");
if($row['status']==1 && $row['daystatus']==0){
if(empty($money_rate))$money_rate = $row['rate'];
return ['typeid'=>$typeid, 'typename'=>$typename, 'plugin'=>$row['plugin'], 'channel'=>$channel, 'subchannel'=>0, 'rate'=>$money_rate, 'apptype'=>$row['apptype'], 'mode'=>$row['mode'], 'paymin'=>$row['paymin'], 'paymax'=>$row['paymax']];
}
}
}else{
//未设置用户组
$row=$DB->getRow("SELECT id,plugin,status,rate,apptype,mode,paymin,paymax FROM pre_channel WHERE type='$typeid' AND status=1 AND daystatus=0 ORDER BY rand() LIMIT 1");
if($row){
return ['typeid'=>$typeid, 'typename'=>$typename, 'plugin'=>$row['plugin'], 'channel'=>$row['id'], 'subchannel'=>0, 'rate'=>$row['rate'], 'apptype'=>$row['apptype'], 'mode'=>$row['mode'], 'paymin'=>$row['paymin'], 'paymax'=>$row['paymax']];
}
}
return false;
}
// 获取当前商户可用支付方式
static public function getTypes($uid, $gid=0){
global $DB;
if(checkmobile()==true){
$sqls = " AND (device=0 OR device=2)";
}else{
$sqls = " AND (device=0 OR device=1)";
}
$rows = $DB->getAll("SELECT * FROM pre_type WHERE status=1{$sqls} ORDER BY id ASC");
$paytype = [];
foreach($rows as $row){
$paytype[$row['id']] = $row;
}
if($gid>0)$groupinfo=$DB->getColumn("SELECT info FROM pre_group WHERE gid='$gid' LIMIT 1");
if(!$groupinfo)$groupinfo=$DB->getColumn("SELECT info FROM pre_group WHERE gid=0 LIMIT 1");
if($groupinfo){
$info = json_decode($groupinfo,true);
foreach($info as $id=>$row){
if(!isset($paytype[$id]))continue;
if($row['channel']==0){
unset($paytype[$id]);
}elseif($row['channel']==-1){
$channel=$DB->getRow("SELECT rate,status FROM pre_channel WHERE type='$id' AND status=1 LIMIT 1");
if(!$channel){
unset($paytype[$id]);
}elseif(empty($row['rate'])){
$paytype[$id]['rate']=$channel['rate'];
}else{
$paytype[$id]['rate']=$row['rate'];
}
}elseif($row['channel']==-2){
$channel=$DB->getRow("SELECT A.id,A.status,rate FROM pre_subchannel B INNER JOIN pre_channel A ON B.channel=A.id WHERE B.uid='$uid' AND A.type='$id' AND A.status=1 AND B.status=1 LIMIT 1");
if(!$channel){
unset($paytype[$id]);
}elseif(empty($row['rate'])){
$paytype[$id]['rate']=$channel['rate'];
}else{
$paytype[$id]['rate']=$row['rate'];
}
}else{
if($row['type']=='roll'){
$status=$DB->getColumn("SELECT status FROM pre_roll WHERE id='{$row['channel']}' LIMIT 1");
}else{
$status=$DB->getColumn("SELECT status FROM pre_channel WHERE id='{$row['channel']}' LIMIT 1");
}
if(!$status || $status==0)unset($paytype[$id]);
else $paytype[$id]['rate']=$row['rate'];
}
}
}else{
foreach($paytype as $id=>$row){
$status=$DB->getColumn("SELECT status FROM pre_channel WHERE type='$id' AND status=1 limit 1");
if(!$status || $status==0)unset($paytype[$id]);
else{
$paytype[$id]['rate']=$DB->getColumn("SELECT rate FROM pre_channel WHERE type='$id' AND status=1 limit 1");
}
}
}
return $paytype;
}
//根据轮询组ID获取支付通道ID
static private function getChannelFromRoll($channel, $money){
global $DB;
$row=$DB->getRow("SELECT * FROM pre_roll WHERE id='$channel' LIMIT 1");
if($row['status']==1){
$info = self::rollinfo_decode($row['info'],true);
//先根据支付金额与限额过滤可用支付通道
$channelids = [];
foreach($info as $inforow){
$channelids[] = $inforow['name'];
}
$channelids = implode(',',$channelids);
$rows=$DB->getAll("SELECT id,paymin,paymax FROM pre_channel WHERE id IN ($channelids) AND status=1 AND daystatus=0");
$newids = [];
foreach($rows as $channelrow){
if($money>0 && !empty($channelrow['paymin']) && $channelrow['paymin']>0 && $money<$channelrow['paymin'])continue;
if($money>0 && !empty($channelrow['paymax']) && $channelrow['paymax']>0 && $money>$channelrow['paymax'])continue;
$newids[] = $channelrow['id'];
}
if(count($newids)==0)return false;
$newinfo = [];
foreach($info as $inforow){
if(in_array($inforow['name'], $newids))$newinfo[]=$inforow;
}
if($row['kind']==2){
return $newids[0];
}elseif($row['kind']==1){
$channel = self::random_weight($newinfo);
}else{
$channel = $newinfo[$row['index']]['name'];
$index = ($row['index'] + 1) % count($newinfo);
$DB->exec("UPDATE pre_roll SET `index`='$index' WHERE id='{$row['id']}'");
}
return $channel;
}
return false;
}
//解析轮询组info
static private function rollinfo_decode($content){
$result = [];
$arr = explode(',',$content);
foreach($arr as $row){
$a = explode(':',$row);
$result[] = ['name'=>$a[0], 'weight'=>$a[1]];
}
return $result;
}
//加权随机
static private function random_weight($arr){
$weightSum = 0;
foreach ($arr as $value) {
$weightSum += intval($value['weight']);
}
if($weightSum<=0)return false;
$randNum = mt_rand(1, $weightSum);
foreach ($arr as $v) {
if ($randNum <= $v['weight']) {
return $v['name'];
}
$randNum -=$v['weight'];
}
}
}
+194
View File
@@ -0,0 +1,194 @@
<?php
namespace lib;
/**
* 极验3.0 lib
*/
class GeetestLib
{
const SDK_VERSION = 'php_3.0.0';
const JSON_FORMAT = "1";
private $geetest_id;
private $geetest_key;
public function __construct($geetest_id, $geetest_key) {
$this->geetest_id = $geetest_id;
$this->geetest_key = $geetest_key;
}
//验证初始化
public function pre_process($params) {
if(!empty($this->geetest_id) && !empty($this->geetest_key)){
return $this->pre_process_api($params);
}else{
return $this->pre_process_demo($params);
}
}
private function pre_process_api($params) {
$public_params = [
'digestmod' => 'md5',
'gt' => $this->geetest_id,
'sdk' => self::SDK_VERSION,
'json_format' => self::JSON_FORMAT
];
$params = array_merge($params, $public_params);
$url = 'http://api.geetest.com/register.php?' . http_build_query($params);
$res = get_curl($url);
$arr = json_decode($res, true);
if($arr && isset($arr['challenge'])){
return $this->success_process($arr['challenge']);
}else{
return $this->failback_process();
}
}
private function success_process($challenge) {
$challenge = md5($challenge . $this->geetest_key);
$result = array(
'success' => 1,
'gt' => $this->geetest_id,
'challenge' => $challenge,
'new_captcha'=>true
);
return $result;
}
private function failback_process() {
$challenge = md5(uniqid(mt_rand(), true) . microtime());
$result = array(
'success' => 0,
'gt' => !empty($this->geetest_id) ? $this->geetest_id : 'e10adc3949ba59abbe56e057f20f883e',
'challenge' => $challenge,
'new_captcha'=>true
);
return $result;
}
private function pre_process_demo($params) {
$url = 'https://www.geetest.com/demo/gt/register-fullpage?t=' . time() . "123";
$referer = 'https://www.geetest.com/demo/slide-popup.html';
$data = get_curl($url, 0, $referer);
$arr = json_decode($data, true);
if($arr && isset($arr['challenge'])){
return $arr;
}else{
return $this->failback_process();
}
}
//正常流程下(即验证初始化成功),二次验证
public function success_validate($challenge, $validate, $seccode, $params) {
if(!empty($this->geetest_id) && !empty($this->geetest_key)){
return $this->success_validate_api($challenge, $validate, $seccode, $params);
}else{
return $this->success_validate_demo($challenge, $validate, $seccode);
}
}
private function success_validate_api($challenge, $validate, $seccode, $params) {
if (!$this->check_validate($challenge, $validate)) {
return false;
}
$public_params = [
'seccode' => $seccode,
'challenge' => $challenge,
'captchaid' => $this->geetest_id,
'sdk' => self::SDK_VERSION,
'json_format' => self::JSON_FORMAT
];
$params = array_merge($params, $public_params);
$url = 'http://api.geetest.com/validate.php';
$res = get_curl($url, http_build_query($params));
$arr = json_decode($res, true);
if($arr && isset($arr['seccode'])){
if($arr['seccode'] == md5($seccode)){
return true;
}
}
return false;
}
private function check_validate($challenge, $validate) {
if (strlen($validate) != 32) {
return false;
}
if (md5($this->geetest_key . 'geetest' . $challenge) != $validate) {
return false;
}
return true;
}
private function success_validate_demo($challenge, $validate, $seccode) {
$params = [
'geetest_challenge' => $challenge,
'geetest_validate' => $validate,
'geetest_seccode' => $seccode
];
$url = 'https://www.geetest.com/demo/gt/validate-fullpage';
$referer = 'https://www.geetest.com/demo/slide-popup.html';
$data = get_curl($url, http_build_query($params), $referer);
$arr = json_decode($data, true);
if($arr && $arr['status'] == 'success'){
return true;
}
return false;
}
//异常流程下(即验证初始化失败,宕机模式),二次验证
public function fail_validate($challenge, $validate, $seccode) {
if(md5($challenge) == $validate){
return true;
}else{
return false;
}
}
public function gt4_validate($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output) {
if(!empty($this->geetest_id) && !empty($this->geetest_key)){
return $this->gt4_validate_api($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output);
}else{
return $this->gt4_validate_demo($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output);
}
}
private function gt4_validate_api($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output){
$url = 'http://gcaptcha4.geetest.com/validate?captcha_id='.$captcha_id;
$param = [
'lot_number' => $lot_number,
'pass_token' => $pass_token,
'gen_time' => $gen_time,
'captcha_output' => $captcha_output
];
$param['sign_token'] = hash_hmac('sha256', $param['lot_number'], $this->geetest_key);
$data = get_curl($url, http_build_query($param));
$arr = json_decode($data, true);
if(isset($arr['status']) && $arr['status']=='success'){
if(isset($arr['result']) && $arr['result'] == 'success'){
return true;
}
}
return false;
}
private function gt4_validate_demo($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output){
global $clientip;
$url = 'http://gt4.geetest.com/demov4/demo/login';
$param = [
'captcha_id' => $captcha_id,
'lot_number' => $lot_number,
'pass_token' => $pass_token,
'gen_time' => $gen_time,
'captcha_output' => $captcha_output
];
$referer = 'http://gt4.geetest.com/demov4/invisible-bind-zh.html';
$httpheader[] = "X-Real-IP: ".$clientip;
$httpheader[] = "X-Forwarded-For: ".$clientip;
$data = get_curl($url.'?'.http_build_query($param),0,$referer,0,0,0,0,$httpheader);
$arr = json_decode($data, true);
if(isset($arr['result']) && $arr['result'] == 'success'){
return true;
}
return false;
}
}
+172
View File
@@ -0,0 +1,172 @@
<?php
namespace lib;
use Exception;
class MsgNotice
{
public static function send($scene, $uid, $param){
global $DB, $conf;
$scene_all = ['complain', 'mchrisk'];
if($uid == 0){
if(in_array($scene, $scene_all)){
$switch = self::getMessageSwitch($scene.'_all');
}else{
$switch = self::getMessageSwitch($scene);
}
if($switch == 1){
$receiver = $conf['mail_recv']?$conf['mail_recv']:$conf['mail_name'];
return self::send_mail_msg($scene, $receiver, $param);
}
}else{
$userrow = $DB->find('user', 'phone,email,wx_uid,msgconfig', ['uid'=>$uid]);
$userrow['msgconfig'] = unserialize($userrow['msgconfig']);
if($scene == 'order' && $userrow['msgconfig']['order_money']>0 && $param['money']<$userrow['msgconfig']['order_money']) return false;
if($scene == 'balance') $param['msgmoney'] = $userrow['msgconfig']['balance_money'];
if($userrow['msgconfig'][$scene] == 1 && !empty($userrow['wx_uid'])){
return self::send_wechat_tplmsg($scene, $userrow['wx_uid'], $param);
}elseif($userrow['msgconfig'][$scene] == 2 && !empty($userrow['email']) && self::getMessageSwitch($scene) == 1){
return self::send_mail_msg($scene, $userrow['email'], $param);
}elseif($userrow['msgconfig'][$scene] == 3 && !empty($userrow['phone'])){
if($scene == 'balance'){
$tpl_code = $conf['sms_tpl_balance'];
$tpl_param = ['code'=>$param['msgmoney']];
}elseif($scene == 'complain'){
$tpl_code = $conf['sms_tpl_complain'];
$tpl_param = ['code'=>$param['trade_no']];
}
if(!empty($tpl_code)){
return send_sms_common($userrow['phone'], $tpl_code, $tpl_param);
}
}
if(in_array($scene, $scene_all)){
$switch = self::getMessageSwitch($scene.'_all');
if($switch == 1){
$receiver = $conf['mail_recv']?$conf['mail_recv']:$conf['mail_name'];
return self::send_mail_msg($scene, $receiver, $param);
}
}
}
return false;
}
public static function send_wechat_tplmsg($scene, $openid, $param){
global $conf, $siteurl, $CACHE;
$wid = $conf['login_wx'];
if($scene == 'order'){
$template_id = $conf['wxnotice_tpl_order'];
if(strlen($param['out_trade_no']) > 32) $param['out_trade_no'] = substr($param['out_trade_no'], 0, 32);
if(mb_strlen($param['name']) > 20) $param['name'] = mb_substr($param['name'], 0, 20);
$data = [];
if($conf['wxnotice_tpl_order_no']) $data[$conf['wxnotice_tpl_order_no']] = ['value'=>$param['trade_no']];
if($conf['wxnotice_tpl_order_name']) $data[$conf['wxnotice_tpl_order_name']] = ['value'=>$param['name']];
if($conf['wxnotice_tpl_order_money']) $data[$conf['wxnotice_tpl_order_money']] = ['value'=>'¥'.$param['money']];
if($conf['wxnotice_tpl_order_time']) $data[$conf['wxnotice_tpl_order_time']] = ['value'=>$param['time']];
if($conf['wxnotice_tpl_order_outno']) $data[$conf['wxnotice_tpl_order_outno']] = ['value'=>$param['out_trade_no']];
$jumpurl = $siteurl.'user/order.php';
}elseif($scene == 'settle'){
$template_id = $conf['wxnotice_tpl_settle'];
$data = [];
if($conf['wxnotice_tpl_settle_type']) $data[$conf['wxnotice_tpl_settle_type']] = ['value'=>'结算成功'];
if($conf['wxnotice_tpl_settle_account']) $data[$conf['wxnotice_tpl_settle_account']] = ['value'=>$param['account']];
if($conf['wxnotice_tpl_settle_money']) $data[$conf['wxnotice_tpl_settle_money']] = ['value'=>'¥'.$param['money']];
if($conf['wxnotice_tpl_settle_realmoney']) $data[$conf['wxnotice_tpl_settle_realmoney']] = ['value'=>'¥'.$param['realmoney']];
if($conf['wxnotice_tpl_settle_time']) $data[$conf['wxnotice_tpl_settle_time']] = ['value'=>$param['time']];
$jumpurl = isset($param['jumpurl']) ? $param['jumpurl'] : $siteurl.'user/settle.php';
}elseif($scene == 'login'){
$template_id = $conf['wxnotice_tpl_login'];
$data = [];
if($conf['wxnotice_tpl_login_user']) $data[$conf['wxnotice_tpl_login_user']] = ['value'=>$param['user']];
if($conf['wxnotice_tpl_login_time']) $data[$conf['wxnotice_tpl_login_time']] = ['value'=>$param['time']];
if($conf['wxnotice_tpl_login_name']) $data[$conf['wxnotice_tpl_login_name']] = ['value'=>$conf['sitename']];
if($conf['wxnotice_tpl_login_ip']) $data[$conf['wxnotice_tpl_login_ip']] = ['value'=>$param['clientip']];
if($conf['wxnotice_tpl_login_iploc']) $data[$conf['wxnotice_tpl_login_iploc']] = ['value'=>$param['ipinfo']];
$jumpurl = $siteurl.'user/';
}elseif($scene == 'complain'){
$template_id = $conf['wxnotice_tpl_complain'];
$data = [];
if(mb_strlen($param['name']) > 20) $param['name'] = mb_substr($param['name'], 0, 20);
if(mb_strlen($param['reason']) > 20) $param['reason'] = mb_substr($param['reason'], 0, 20);
if($conf['wxnotice_tpl_complain_order_no']) $data[$conf['wxnotice_tpl_complain_order_no']] = ['value'=>$param['trade_no']];
if($conf['wxnotice_tpl_complain_time']) $data[$conf['wxnotice_tpl_complain_time']] = ['value'=>$param['time']];
if($conf['wxnotice_tpl_complain_reason']) $data[$conf['wxnotice_tpl_complain_reason']] = ['value'=>$param['content']];
if($conf['wxnotice_tpl_complain_type']) $data[$conf['wxnotice_tpl_complain_type']] = ['value'=>$param['type']];
if($conf['wxnotice_tpl_complain_name']) $data[$conf['wxnotice_tpl_complain_name']] = ['value'=>$param['name']];
$jumpurl = $siteurl.'user/';
}elseif($scene == 'balance'){
$template_id = $conf['wxnotice_tpl_balance'];
$data = [];
if($conf['wxnotice_tpl_balance_user']) $data[$conf['wxnotice_tpl_balance_user']] = ['value'=>$param['user']];
if($conf['wxnotice_tpl_balance_time']) $data[$conf['wxnotice_tpl_balance_time']] = ['value'=>$param['time']];
if($conf['wxnotice_tpl_balance_money']) $data[$conf['wxnotice_tpl_balance_money']] = ['value'=>$param['money']];
if($conf['wxnotice_tpl_balance_msg']) $data[$conf['wxnotice_tpl_balance_msg']] = ['value'=>'为避免造成订单失败,请及时充值'];
$jumpurl = $siteurl.'user/';
}
if(empty($template_id) || empty($wid)) return false;
$wechat = new \lib\wechat\WechatAPI($wid);
try{
return $wechat->sendTemplateMessage($openid, $template_id, $jumpurl, $data);
}catch(Exception $e){
$errmsg = $e->getMessage();
$CACHE->save('wxtplerrmsg', ['errmsg'=>$errmsg, 'time'=>date('Y-m-d H:i:s')], 86400);
//echo $errmsg;
return false;
}
}
private static function send_mail_msg($scene, $receiver, $param){
global $conf, $CACHE;
[$title, $content] = self::get_msg_tpl($scene, $param);
if(empty($content)) return;
$result = send_mail($receiver, $title, $content);
if($result === true) return true;
if(!empty($result)){
$CACHE->save('mailerrmsg', ['errmsg'=>$result, 'time'=>date('Y-m-d H:i:s')], 86400);
}
return false;
}
private static function get_msg_tpl($scene, $param){
global $conf;
if($scene == 'regaudit'){
$title = '新注册商户待审核提醒';
$content = '尊敬的'.$conf['sitename'].'管理员,网站有新注册的商户待审核,请及时前往用户列表审核处理。<br/>商户ID'.$param['uid'].'<br/>注册账号:'.$param['account'].'<br/>注册时间:'.date('Y-m-d H:i:s');
}elseif($scene == 'apply'){
$title = '新的提现待处理提醒';
$content = '尊敬的'.$conf['sitename'].'管理员,商户'.$param['uid'].'发起了手动提现申请,请及时处理。<br/>商户ID'.$param['uid'].'<br/>提现方式:'.$param['type'].'<br/>提现金额:'.$param['realmoney'].'<br/>提交时间:'.date('Y-m-d H:i:s');
}elseif($scene == 'domain'){
$title = '新的授权支付域名待审核提醒';
$content = '尊敬的'.$conf['sitename'].'管理员,商户'.$param['uid'].'提交了新的授权支付域名,请及时审核处理。<br/>商户ID'.$param['uid'].'<br/>授权域名:'.$param['domain'].'<br/>提交时间:'.date('Y-m-d H:i:s');
}elseif($scene == 'order'){
$title = '新订单通知 - '.$conf['sitename'];
$content = '尊敬的商户,您有一条新订单通知。<br/>商品名称:'.$param['name'].'<br/>订单金额:¥'.$param['money'].'<br/>支付方式:'.$param['type'].'<br/>商户订单号:'.$param['out_trade_no'].'<br/>系统订单号:'.$param['trade_no'].'<br/>支付完成时间:'.$param['time'];
}elseif($scene == 'settle'){
$title = '结算完成通知 - '.$conf['sitename'];
$content = '尊敬的商户,今日结算已完成,请查收。<br/>结算金额:¥'.$param['money'].'<br/>实际到账:¥'.$param['realmoney'].'<br/>结算账号:'.$param['account'].'<br/>结算完成时间:'.$param['time'];
}elseif($scene == 'login'){
$title = '账号登录通知 - '.$conf['sitename'];
$content = '尊敬的商户,您的账号<b>'.$param['user'].'</b>已于'.$param['time'].'成功登录到商户平台。<br/>登录IP'.$param['clientip'].'<br/>登录时间:'.$param['time'];
}elseif($scene == 'complain'){
$title = '支付交易投诉通知 - '.$conf['sitename'];
$content = '尊敬的商户,'.$param['type'].'<br/>系统订单号:'.$param['trade_no'].'<br/>投诉原因:'.$param['title'].'<br/>投诉详情:'.$param['content'].'<br/>商品名称:'.$param['ordername'].'<br/>订单金额:¥'.$param['money'].'<br/>投诉时间:'.$param['time'];
}elseif($scene == 'mchrisk'){
$title = '渠道商户违规处置通知 - '.$conf['sitename'];
$content = '尊敬的商户,您有新的渠道商户违规处置记录!<br/>渠道子商户号:'.$param['mchid'].'<br/>商户名称:'.$param['mchname'].'<br/>风险类型:'.$param['risk_desc'].'<br/>处罚方案:'.$param['punish_type'].''.$param['punish_desc'].'<br/>记录时间:'.$param['punish_time'];
}elseif($scene == 'balance'){
$title = '商户余额不足提醒 - '.$conf['sitename'];
$content = '尊敬的商户,您的手续费余额不足'.$param['msgmoney'].'元,为避免造成订单失败请及时充值。<br/>当前余额:'.$param['money'].'元';
}
return [$title, $content];
}
private static function getMessageSwitch($scene){
global $conf;
if(isset($conf['msgconfig_'.$scene])){
return $conf['msgconfig_'.$scene];
}
return false;
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
namespace lib;
/*
* 快捷登录接口
*/
class Oauth{
private $apiurl;
private $appid;
private $appkey;
private $callback;
function __construct($config){
$this->apiurl = $config['apiurl'].'connect.php';
$this->appid = $config['appid'];
$this->appkey = $config['appkey'];
$this->callback = $config['callback'];
}
//获取登录跳转url
public function login($type){
//-------生成唯一随机串防CSRF攻击
$state = md5(uniqid(rand(), TRUE));
$_SESSION['Oauth_state'] = $state;
//-------构造请求参数列表
$keysArr = array(
"act" => "login",
"appid" => $this->appid,
"appkey" => $this->appkey,
"type" => $type,
"redirect_uri" => $this->callback,
"state" => $state
);
$login_url = $this->apiurl.'?'.http_build_query($keysArr);
$response = get_curl($login_url);
$arr = json_decode($response,true);
return $arr;
}
//登录成功返回网站
public function callback(){
//-------请求参数列表
$keysArr = array(
"act" => "callback",
"appid" => $this->appid,
"appkey" => $this->appkey,
"code" => $_GET['code']
);
//------构造请求access_token的url
$token_url = $this->apiurl.'?'.http_build_query($keysArr);
$response = get_curl($token_url);
$arr = json_decode($response,true);
return $arr;
}
//查询用户信息
public function query($type, $social_uid){
//-------请求参数列表
$keysArr = array(
"act" => "query",
"appid" => $this->appid,
"appkey" => $this->appkey,
"type" => $type,
"social_uid" => $social_uid
);
//------构造请求access_token的url
$token_url = $this->apiurl.'?'.http_build_query($keysArr);
$response = get_curl($token_url);
$arr = json_decode($response,true);
return $arr;
}
}
+128
View File
@@ -0,0 +1,128 @@
<?php
namespace lib;
class Order
{
public static function freeze($trade_no){
global $DB;
$row = $DB->find('order', 'uid,getmoney,status,channel', ['trade_no'=>$trade_no]);
if(!$row)
return ['code'=>-1, 'msg'=>'当前订单不存在!'];
if($row['status']!=1)
return ['code'=>-1, 'msg'=>'只支持冻结已支付状态的订单'];
$channel = \lib\Channel::get($row['channel']);
if($channel['mode']==1)
return ['code'=>-1, 'msg'=>'当前支付通道为商户直清,不支持冻结'];
if($row['getmoney']>0){
changeUserMoney($row['uid'], $row['getmoney'], false, '订单冻结', $trade_no);
$DB->exec("update pre_order set status='3' where trade_no='$trade_no'");
}
return ['code'=>0, 'msg'=>'已成功从UID:'.$row['uid'].'冻结'.$row['getmoney'].'元余额'];
}
public static function unfreeze($trade_no){
global $DB;
$row = $DB->find('order', 'uid,getmoney,status,channel', ['trade_no'=>$trade_no]);
if(!$row)
return ['code'=>-1, 'msg'=>'当前订单不存在!'];
if($row['status']!=3)
return ['code'=>-1, 'msg'=>'只支持解冻已冻结状态的订单'];
$channel = \lib\Channel::get($row['channel']);
if($channel['mode']==1)
return ['code'=>-1, 'msg'=>'当前支付通道为商户直清,不支持冻结'];
if($row['getmoney']>0){
changeUserMoney($row['uid'], $row['getmoney'], true, '订单解冻', $trade_no);
$DB->exec("update pre_order set status='1' where trade_no='$trade_no'");
}
return ['code'=>0, 'msg'=>'已成功为UID:'.$row['uid'].'恢复'.$row['getmoney'].'元余额'];
}
public static function refund_info($trade_no, $api = 0, $uid = 0){
global $DB;
$where = ['trade_no'=>$trade_no];
if($uid > 0) $where['uid'] = $uid;
$order = $DB->find('order', '*', $where);
if(!$order)
return ['code'=>-1, 'msg'=>'当前订单不存在!'];
if(!in_array($order['status'], [1,2,3]))
return ['code'=>-1, 'msg'=>'该订单状态不支持退款!'];
if($order['status'] == 2 && empty($order['refundmoney'])) return ['code'=>-1, 'msg'=>'该订单已退款!'];
if($order['refundmoney'] > 0 && $order['refundmoney'] >= $order['realmoney']) return ['code'=>-1, 'msg'=>'该订单已全额退款!'];
$money = !empty($order['refundmoney']) ? round($order['realmoney'] - $order['refundmoney'], 2) : $order['realmoney'];
if($api==1){
if(!$order['api_trade_no']) return ['code'=>-1, 'msg'=>'接口订单号不存在'];
$channel = \lib\Channel::get($order['channel']);
if(!$channel) return ['code'=>-1, 'msg'=>'当前支付通道信息不存在'];
if(\lib\Plugin::isrefund($channel['plugin'])==false){
return ['code'=>-1, 'msg'=>'当前支付通道不支持API退款'];
}
}
return ['code'=>0, 'money'=>$money];
}
public static function refund($refund_no, $trade_no, $money, $api = 0, $uid = 0, $out_refund_no = null){
global $DB, $order, $conf;
$where = ['trade_no'=>$trade_no];
if($uid > 0) $where['uid'] = $uid;
$order = $DB->find('order', '*', $where);
if(!$order)
return ['code'=>-1, 'msg'=>'当前订单不存在!'];
if(!in_array($order['status'], [1,2,3]))
return ['code'=>-1, 'msg'=>'该订单状态不支持退款!'];
if($money>$order['realmoney']) return ['code'=>-1, 'msg'=>'退款金额不能大于订单金额'];
if(!$order['api_trade_no']) return ['code'=>-1, 'msg'=>'接口订单号不存在'];
if($order['status'] == 2 && empty($order['refundmoney'])) return ['code'=>-1, 'msg'=>'该订单已退款!'];
if($order['refundmoney'] > 0 && $order['refundmoney'] >= $order['realmoney']) return ['code'=>-1, 'msg'=>'该订单已全额退款!'];
if($order['refundmoney'] > 0 && $money > round($order['realmoney'] - $order['refundmoney'], 2)) return ['code'=>-1, 'msg'=>'退款金额不能超过该订单剩余可退款金额!'];
$refunded = $order['refundmoney'];
if(!$out_refund_no) $out_refund_no = $refund_no;
$mode = $DB->findColumn('channel', 'mode', ['id'=>$order['channel']]);
if($order['status'] == 3 || $mode == 1){
$reducemoney = 0;
}elseif($conf['refund_fee_type']==1 && $money == $order['realmoney']){
$reducemoney = $order['realmoney'];
}elseif(!$conf['refund_fee_type'] && ($money == $order['realmoney'] || $money >= $order['getmoney'])){
$reducemoney = $order['getmoney'];
}else{
$reducemoney = $money;
}
if($uid > 0 && $reducemoney > 0){
$usermoney = $DB->findColumn('user', 'money', ['uid'=>$uid]);
if($reducemoney > $usermoney){
return ['code'=>-1, 'msg'=>'商户余额不足,请先充值'];
}
}
if($api == 1){
$message = null;
if(!\lib\Plugin::refund($refund_no, $trade_no, $money, $message)){
return ['code'=>-1, 'msg'=>'退款失败:'.$message];
}
}
if($reducemoney > 0){
if($order['tid'] == 2){
$param = json_decode($order['param'], true);
if(isset($param['uid'])){
$order['uid'] = $param['uid'];
}
}
changeUserMoney($order['uid'], $reducemoney, false, '订单退款', $trade_no);
}
if($api == 1){
$refundmoney = !empty($refunded) ? round($refunded + $money, 2) : $money;
$DB->update('order', ['status'=>2, 'refundmoney'=>$refundmoney], ['trade_no'=>$trade_no]);
$DB->insert('refundorder', ['refund_no'=>$refund_no, 'out_refund_no'=>$out_refund_no, 'trade_no'=>$trade_no, 'uid'=>$order['uid'], 'money'=>$money, 'reducemoney'=>$reducemoney, 'addtime'=>date('Y-m-d H:i:s'), 'endtime'=>date('Y-m-d H:i:s'), 'status'=>1]);
}else{
$DB->update('order', ['status'=>2], ['trade_no'=>$trade_no]);
}
return ['code'=>0, 'refund_no'=>$refund_no, 'out_refund_no'=>$out_refund_no, 'trade_no'=>$trade_no, 'out_trade_no'=>$order['out_trade_no'], 'uid'=>$order['uid'], 'money'=>$money, 'reducemoney'=>$reducemoney];
}
}
+552
View File
@@ -0,0 +1,552 @@
<?php
namespace lib;
use Exception;
class Payment {
//生成待签名字符串
static private function getSignContent($data){
ksort($data);
$signStr = '';
foreach ($data as $k => $v) {
if(is_array($v) || isEmpty($v) || $k == 'sign' || $k == 'sign_type') continue;
$signStr .= $k . '=' . $v . '&';
}
$signStr = substr($signStr, 0, -1);
return $signStr;
}
//生成签名
static public function makeSign($data, $md5key) {
$sign_type = $data['sign_type'] ? $data['sign_type'] : 'MD5';
$signStr = self::getSignContent($data);
if($sign_type == 'RSA'){
global $conf;
$private_key = base64ToPem($conf['private_key'], 'PRIVATE KEY');
$pkey = openssl_pkey_get_private($private_key);
if(!$pkey) return false;
openssl_sign($signStr, $sign, $pkey, OPENSSL_ALGO_SHA256);
return base64_encode($sign);
}else{
$sign = md5($signStr . $md5key);
return $sign;
}
}
//验证签名
static public function verifySign($data, $md5key, $publicKey) {
if(!isset($data['sign'])) throw new Exception('缺少签名参数');
$sign_type = $data['sign_type'] ? $data['sign_type'] : 'MD5';
if($sign_type == 'RSA'){
$public_key = base64ToPem($publicKey, 'PUBLIC KEY');
$pkey = openssl_pkey_get_public($public_key);
if(!$pkey) throw new Exception('签名校验失败,商户公钥错误');
$signStr = self::getSignContent($data);
$result = openssl_verify($signStr, base64_decode($data['sign']), $pkey, OPENSSL_ALGO_SHA256);
return $result === 1;
}else{
$sign = self::makeSign($data, $md5key);
return $sign === $data['sign'];
}
}
// 页面支付返回信息
static public function echoDefault($result){
global $cdnpublic,$order,$conf,$sitename,$ordername,$siteurl;
$type = $result['type'];
if(!$type) return false;
switch($type){
case 'jump': //跳转
$html_text = '<script>window.location.replace(\''.$result['url'].'\');</script>';
if(isset($result['submit']) && $result['submit']){
submitTemplate($html_text);
}else{
echo $html_text;
}
break;
case 'html': //显示html
$html_text = $result['data'];
if(isset($result['submit']) && $result['submit'] && substr($html_text, 0, 6) == '<form '){
submitTemplate($html_text);
}else{
echo $html_text;
}
break;
case 'json': //显示JSON
echo json_encode($result['data']);
break;
case 'page': //显示指定页面
include_once SYSTEM_ROOT.'txprotect.php';
if(isset($result['data'])) extract($result['data']);
if($conf['pageordername']==1)$order['name']=$ordername?$ordername:'onlinepay';
include PAYPAGE_ROOT.$result['page'].'.php';
break;
case 'qrcode': //扫码页面
if($result['page'] == 'alipay_qrcode' && !empty($conf['alipay_qrcode_url'])){
if(strpos($result['url'], $siteurl)===0){
$result['url'] = $conf['alipay_qrcode_url'].substr($result['url'], strlen($siteurl));
}elseif(!empty($conf['localurl_alipay']) && strpos($result['url'], $conf['localurl_alipay'])===0){
$result['url'] = $conf['alipay_qrcode_url'].substr($result['url'], strlen($conf['localurl_alipay']));
}
}
case 'scheme': //跳转urlscheme页面
if($result['page'] == 'wxpay_mini') $result['page'] = 'wxpay_h5';
include_once SYSTEM_ROOT.'txprotect.php';
$code_url = $result['url'];
if($conf['pageordername']==1)$order['name']=$ordername?$ordername:'onlinepay';
if($conf['wework_payopen'] == 1 && ($result['page'] == 'wxpay_wap' && strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger')===false || $result['page'] == 'wxpay_qrcode' && checkmobile())){
$code_url_wxkf = self::getWxkfPayUrl($code_url);
if($code_url_wxkf){
$code_url = $code_url_wxkf;
include PAYPAGE_ROOT.'wxpay_h5.php';
break;
}
}
include PAYPAGE_ROOT.$result['page'].'.php';
break;
case 'return': //同步回调
returnTemplate($result['url']);
break;
case 'error': //错误提示
sysmsg($result['msg']);
break;
default:break;
}
}
// API支付返回信息
static public function echoJson($result){
global $order,$siteurl;
if(!$result) return false;
$type = $result['type'];
if(!$type) return false;
if(defined('API_INIT')){
$json = ['code'=>0, 'trade_no'=>TRADE_NO];
switch($type){
case 'jump': //跳转URL
$json['pay_type'] = 'jump';
$json['pay_info'] = $result['url'];
break;
case 'html': //显示html跳转
$json['pay_type'] = 'html';
$json['pay_info'] = $result['data'];
break;
case 'qrcode': //扫码支付
$json['pay_type'] = 'qrcode';
$json['pay_info'] = $result['url'];
break;
case 'scheme': //小程序H5跳转
$json['pay_type'] = 'urlscheme';
$json['pay_info'] = $result['url'];
break;
case 'jsapi': //JSAPI支付
$json['pay_type'] = 'jsapi';
$json['pay_info'] = $result['data'];
break;
case 'app': //APP支付
$json['pay_type'] = 'app';
$json['pay_info'] = $result['data'];
break;
case 'scan': //付款码支付
$json['pay_type'] = 'scan';
$json['pay_info'] = $result['data'];
break;
case 'wxplugin': //微信小程序插件支付
$json['pay_type'] = 'wxplugin';
$json['pay_info'] = $result['data'];
break;
case 'wxapp': //跳转微信小程序支付
$json['pay_type'] = 'wxapp';
$json['pay_info'] = $result['data'];
break;
case 'error':
$json['code'] = -2;
$json['msg'] = $result['msg'];
break;
default:
$json['pay_type'] = 'jump';
$json['pay_info'] = $siteurl.'pay/submit/'.TRADE_NO.'/';
break;
}
if($json['code'] == 0){
if(is_array($json['pay_info'])) $json['pay_info'] = json_encode($json['pay_info']);
$json['timestamp'] = time().'';
$json['sign_type'] = 'RSA';
$json['sign'] = self::makeSign($json, null);
}
exit(json_encode($json));
}else{
$json = ['code'=>1, 'trade_no'=>TRADE_NO];
switch($type){
case 'jump': //跳转URL
$json['payurl'] = $result['url'];
break;
case 'html': //显示html跳转
$json['html'] = $result['data'];
break;
case 'qrcode': //扫码支付
$json['qrcode'] = $result['url'];
break;
case 'scheme': //小程序H5跳转
$json['urlscheme'] = $result['url'];
break;
case 'error':
$json['code'] = -2;
$json['msg'] = $result['msg'];
break;
default:
$json['payurl'] = $siteurl.'pay/submit/'.TRADE_NO.'/';
break;
}
exit(json_encode($json));
}
}
// 订单回调处理
static public function processOrder($isnotify, $order, $api_trade_no, $buyer = null, $bill_trade_no = null){
global $DB,$conf,$siteurl;
if($order['status']==0 || $order['status']==4){
if($DB->exec("UPDATE `pre_order` SET `status`=1 WHERE `trade_no`='".$order['trade_no']."'")){
$data = ['endtime'=>'NOW()', 'date'=>'CURDATE()'];
if(!empty($api_trade_no)) $data['api_trade_no'] = $api_trade_no;
if(!empty($buyer)) $data['buyer'] = $buyer;
if(!empty($bill_trade_no)) $data['bill_trade_no'] = $bill_trade_no;
if($order['settle']>0) $data['settle'] = $order['settle'];
$DB->update('order', $data, ['trade_no'=>$order['trade_no']]);
$order['api_trade_no'] = $api_trade_no;
processOrder($order, $isnotify);
}
}elseif(empty($order['api_trade_no']) && !empty($api_trade_no)){
$data = ['api_trade_no'=>$api_trade_no];
if(!empty($buyer)) $data['buyer'] = $buyer;
if(!empty($bill_trade_no)) $data['bill_trade_no'] = $bill_trade_no;
$DB->update('order', $data, ['trade_no'=>$order['trade_no']]);
}elseif(empty($order['buyer']) && !empty($buyer)){
$data['buyer'] = $buyer;
$DB->update('order', $data, ['trade_no'=>$order['trade_no']]);
}
if($isnotify && $order['settle']>0){
$DB->update('order', ['settle'=>$order['settle']], ['trade_no'=>$order['trade_no']]);
}
if(!$isnotify){
include_once SYSTEM_ROOT.'txprotect.php';
if($order['status'] == 2){
$jumpurl = '/payerr.html';
returnTemplate($jumpurl);
return;
}
// 支付完成5分钟后禁止跳转回网站
if(!empty($order['endtime']) && time() - strtotime($order['endtime']) > 300){
$jumpurl = '/payok.html';
}else{
$url=creat_callback($order);
$jumpurl = $url['return'];
}
returnTemplate($jumpurl);
}
}
// 更新订单信息
static public function updateOrder($trade_no, $api_trade_no, $buyer = null, $status = null){
global $DB;
$data = ['api_trade_no'=>$api_trade_no];
if(!empty($buyer)) $data['buyer'] = $buyer;
if($status) $data['status'] = $status;
$DB->update('order', $data, ['trade_no'=>$trade_no]);
}
// 更新订单扩展信息
static public function updateOrderExt($trade_no, $data){
global $DB;
$DB->update('order', ['ext'=>serialize($data)], ['trade_no'=>$trade_no]);
}
// 更新合单状态
static public function updateOrderCombine($trade_no, $sub_orders = null){
global $DB;
$DB->update('order', ['combine'=>1], ['trade_no'=>$trade_no]);
if(!empty($sub_orders)){
$DB->delete('suborder', ['trade_no'=>$trade_no]);
foreach($sub_orders as $data){
$data['trade_no'] = $trade_no;
$data['status'] = 0;
$DB->insert('suborder', $data);
}
}
}
// 更新订单分账接收人
static public function updateOrderProfits($order, $plugin){
global $DB;
$support_plugins = \lib\ProfitSharing\CommUtil::$plugins;
if(in_array($plugin, $support_plugins)){
$psreceiver = null;
if($order['subchannel'] > 0){
$psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver` WHERE `channel`='{$order['channel']}' AND `uid`='{$order['uid']}' AND `subchannel`='{$order['subchannel']}' AND `status`=1 ORDER BY id ASC LIMIT 1");
}
if(!$psreceiver) $psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver` WHERE `channel`='{$order['channel']}' AND `uid`='{$order['uid']}' AND `status`=1 ORDER BY id ASC LIMIT 1");
if(!$psreceiver) $psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver` WHERE `channel`='{$order['channel']}' AND `uid` IS NULL AND `status`=1 ORDER BY id ASC LIMIT 1");
if($psreceiver){
if(!$psreceiver['minmoney'] || $order['realmoney']>=$psreceiver['minmoney']){
$DB->update('order', ['profits'=>$psreceiver['id']], ['trade_no'=>$order['trade_no']]);
return intval($psreceiver['id']);
}
}
}
return 0;
}
// 更新订单分账接收人2
static public function updateOrderProfits2($order, $plugin){
return 0;
}
//支付宝直付通确认结算
public static function alipaydSettle($channel, $order){
$alipay_config = require(PLUGIN_ROOT.'alipayd/inc/config.php');
$alipaySevice = new \Alipay\AlipayTradeService($alipay_config);
if($order['combine'] == 1){
$sub_orders = self::getSubOrders($order['trade_no']);
if(empty($sub_orders)) throw new Exception('子订单数据不存在');
$failnum = 0;
$errmsg = '';
foreach($sub_orders as $sub_order){
if($sub_order['settle'] == 0){
$settle = 0;
try{
$alipaySevice->settle_confirm($sub_order['api_trade_no'], $sub_order['money']);
$settle = 1;
}catch(Exception $e){
if(strpos($e->getMessage(), 'ALREADY_CONFIRM_SETTLE')!==false){
$settle = 1;
}else{
$failnum++;
$errmsg .= $e->getMessage().',';
}
}
if($settle == 1) self::updateSubOrderSettle($sub_order['sub_trade_no'], 1);
}
}
if($failnum > 0) throw new Exception('部分子单结算失败,失败数量:'.$failnum.',失败原因:'.$errmsg);
return true;
}
try{
$alipaySevice->settle_confirm($order['api_trade_no'], $order['realmoney']);
return true;
}catch(Exception $e){
if(strpos($e->getMessage(), 'ALREADY_CONFIRM_SETTLE')!==false){
return true;
}else{
throw $e;
}
}
}
//微信收付通确认结算
public static function wxpaynpSettle($channel, $order){
$wechatpay_config = require(PLUGIN_ROOT.'/wxpaynp/inc/config.php');
if($wechatpay_config['ecommerce']){
if(!$order['profits']){
$client = new \WeChatPay\V3\ProfitsharingService($wechatpay_config);
return $client->unfreeze($order['trade_no'], $order['api_trade_no']);
}else{
throw new Exception('当前订单需要分账,请进入分账订单页面确认分账');
}
}else{
throw new Exception('非电商收付通订单');
}
}
//支付宝预授权资金支付
public static function alipayPreAuthPay($channel, $order){
global $conf;
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$alipaySevice = new \Alipay\AlipayTradeService($alipay_config);
$trade_no = $order['trade_no'];
$bizContent = [
'out_order_no' => $trade_no,
'out_request_no' => $trade_no,
];
$result = $alipaySevice->preAuthQuery($bizContent);
//print_r($result);exit;
if(!isset($result['auth_no'])) throw new Exception('预授权订单查询失败');
if($result['rest_amount'] == 0) throw new Exception('剩余冻结金额为0');
if($result['order_status'] == 'AUTHORIZED'){
$auth_no = $result['auth_no'];
$ordername = !empty($conf['ordername'])?ordername_replace($conf['ordername'],$order['name'],$order['uid'],$trade_no):$order['name'];
$bizContent = [
'out_trade_no' => $trade_no,
'total_amount' => $result['rest_amount'],
'subject' => $ordername,
'product_code' => 'PREAUTH_PAY',
'auth_no' => $auth_no,
'auth_confirm_mode' => 'COMPLETE'
];
return $alipaySevice->scanPay($bizContent);
}else{
throw new Exception('该笔订单非已授权状态,无需支付');
}
}
//支付宝预授权资金解冻
public static function alipayUnfreeze($channel, $order){
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$alipaySevice = new \Alipay\AlipayTradeService($alipay_config);
$trade_no = $order['trade_no'];
$bizContent = [
'out_order_no' => $trade_no,
'out_request_no' => $trade_no,
];
$result = $alipaySevice->preAuthQuery($bizContent);
//print_r($result);exit;
if(!isset($result['auth_no'])) throw new Exception('预授权订单查询失败');
if($result['rest_amount'] == 0) throw new Exception('剩余冻结金额为0');
if($result['order_status'] == 'AUTHORIZED'){
$auth_no = $result['auth_no'];
$bizContent = [
'auth_no' => $auth_no,
'out_request_no' => date("YmdHis").rand(11111,99999),
'amount' => $result['rest_amount'],
'remark' => '解冻资金'
];
return $alipaySevice->preAuthUnfreeze($bizContent);
}else{
throw new Exception('该笔订单非已授权状态,无需解冻');
}
}
//支付宝红包转账
public static function alipayRedPacketTransfer($channel, $payee_user_id, $money, $order_id){
$out_biz_no = date("YmdHis").rand(11111,99999);
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$alipaySevice = new \Alipay\AlipayTransferService($alipay_config);
$alipaySevice->redPacketTansfer($out_biz_no, $money, $payee_user_id, $conf['sitename'], $order_id);
}
//支付宝红包资金退回
public static function alipayRedPacketRefund($channel, $trade_no, $money){
$out_biz_no = date("YmdHis").rand(11111,99999);
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$alipaySevice = new \Alipay\AlipayTransferService($alipay_config);
$alipaySevice->redPacketRefund($out_biz_no, $trade_no, $money);
}
//加锁设置订单扩展数据
public static function lockPayData($trade_no, $func){
global $DB;
$DB->beginTransaction();
$data = $DB->getColumn("SELECT ext FROM pre_order WHERE trade_no=:trade_no FOR UPDATE", [':trade_no'=>$trade_no]);
if($data) {
$DB->rollBack();
return unserialize($data);
}
try{
$data = $func();
}catch(\Exception $e){
$DB->rollBack();
throw $e;
}
if($data){
$DB->update('order', ['ext'=>serialize($data)], ['trade_no' => $trade_no]);
}
$DB->commit();
return $data;
}
//获取微信客服跳转链接
public static function getWxkfPayUrl($pay_url){
global $order, $DB, $conf;
$cookiesid = $_COOKIE['mysid'];
if(!$cookiesid||!preg_match('/^[0-9a-z]{32}$/i', $cookiesid)){
$cookiesid = getSid();
setcookie("mysid", $cookiesid, time() + 2592000, '/');
}
if($conf['wework_paykfid'] > 0){
$wxkfaccount = $DB->getRow("SELECT * FROM pre_wxkfaccount WHERE id=:id", [':id'=>$conf['wework_paykfid']]);
}elseif($conf['wework_paymsgmode'] == 1){
$usekflist = $DB->getAll("SELECT DISTINCT aid FROM pre_wxkflog WHERE `sid`=:sid AND addtime>=:addtime AND status=1", [':sid'=>$cookiesid, ':addtime'=>date("Y-m-d H:i:s", strtotime('-48 hours'))]);
$usekfids = [0];
foreach($usekflist as $usekf){
$usekfids[] = intval($usekf['aid']);
}
$wxkfaccount = $DB->getRow("SELECT A.* FROM pre_wxkfaccount A LEFT JOIN pre_wework B ON A.wid=B.id WHERE A.id NOT IN (".implode(",", $usekfids).") AND B.status=1 ORDER BY A.usetime ASC LIMIT 1");
}else{
$wxkfaccount = $DB->getRow("SELECT A.* FROM pre_wxkfaccount A LEFT JOIN pre_wework B ON A.wid=B.id WHERE B.status=1 ORDER BY A.usetime ASC LIMIT 1");
}
if(!$wxkfaccount) return false;
$DB->insert('wxkflog', ['trade_no'=>$order['trade_no'], 'aid'=>$wxkfaccount['id'], 'sid'=>$cookiesid, 'payurl'=>$pay_url, 'addtime'=>'NOW()']);
$scene_param = 'orderid='.$order['trade_no'].'&money='.$order['realmoney'];
try{
if(!empty($wxkfaccount['url'])){
$kfurl = $wxkfaccount['url'];
$DB->update('wxkfaccount', ['usetime'=>'NOW()'], ['id'=>$wxkfaccount['id']]);
}else{
$wework = new wechat\WeWorkAPI($wxkfaccount['wid']);
$kfurl = $wework->getKFURL($wxkfaccount['openkfid'], 'pay');
$DB->update('wxkfaccount', ['url'=>$kfurl, 'usetime'=>'NOW()'], ['id'=>$wxkfaccount['id']]);
}
$kfurl = 'weixin://biz/ww/kefu/' . $kfurl . '&schema=1';
$kfurl .= '&scene_param='.urlencode($scene_param);
return $kfurl;
}catch(\Exception $e){
sysmsg($e->getMessage());
}
}
//支付宝直付通&微信收付通延迟结算处理
public static function settle_task(){
global $DB;
$orders = $DB->getAll("SELECT A.*,B.plugin FROM pre_order A LEFT JOIN pre_channel B ON A.channel=B.id WHERE A.status=1 AND A.settle=1 AND A.addtime<DATE_SUB(NOW(), INTERVAL 24 HOUR) AND B.plugin in ('alipayd','wxpaynp') ORDER BY A.trade_no ASC LIMIT 10");
foreach($orders as $row){
$trade_no = $row['trade_no'];
$channel = $row['subchannel'] > 0 ? \lib\Channel::getSub($row['subchannel']) : \lib\Channel::get($row['channel'], $DB->findColumn('user', 'channelinfo', ['uid'=>$row['uid']]));
if(!$channel) continue;
try{
if($row['plugin'] == 'alipayd'){
self::alipaydSettle($channel, $row);
}elseif($row['plugin'] == 'wxpaynp'){
self::wxpaynpSettle($channel, $row);
}
$DB->update('order', ['settle'=>2], ['trade_no'=>$trade_no]);
echo $trade_no.' 结算成功<br/>';
}catch(Exception $e){
$errmsg = $e->getMessage();
if(strpos($errmsg, 'ALREADY_CONFIRM_SETTLE')){
$DB->update('order', ['settle'=>2], ['trade_no'=>$trade_no]);
echo $trade_no.' 结算成功<br/>';
continue;
}
$DB->update('order', ['settle'=>3], ['trade_no'=>$trade_no]);
echo $trade_no.' 结算失败,'.$errmsg.'<br/>';
}
}
}
public static function getSubOrders($trade_no){
global $DB;
return $DB->getAll("SELECT * FROM pre_suborder WHERE trade_no=:trade_no", [':trade_no'=>$trade_no]);
}
public static function processSubOrders($trade_no, $sub_orders){
global $DB;
foreach($sub_orders as $data){
$DB->update('suborder', ['status'=>1, 'api_trade_no'=>$data['api_trade_no']], ['sub_trade_no'=>$data['sub_trade_no']]);
}
}
public static function refundSubOrder($sub_trade_no, $refundmoney = null){
global $DB;
$DB->update('suborder', ['status'=>2, 'refundmoney'=>$refundmoney], ['sub_trade_no'=>$sub_trade_no]);
}
public static function updateSubOrderSettle($sub_trade_no, $settle){
global $DB;
$DB->update('suborder', ['settle'=>$settle], ['sub_trade_no'=>$sub_trade_no]);
}
}
+445
View File
@@ -0,0 +1,445 @@
<?php
namespace lib;
class PdoHelper
{
private $sqlPrefix = "pre_";//SQL数据表前缀识别字符
private $db;
private $fetchStyle = \PDO::FETCH_ASSOC;
private $prefix;
private $errorInfo;
/**
* PdoHelper constructor.
*
* @param array $dbconfig 数据库信息
*/
function __construct($dbconfig)
{
$this->prefix = $dbconfig['dbqz'].'_';
try {
$this->db = new \PDO("mysql:host={$dbconfig['host']};dbname={$dbconfig['dbname']};port={$dbconfig['port']}",$dbconfig['user'],$dbconfig['pwd']);
} catch (\Exception $e) {
exit('链接数据库失败:' . $e->getMessage());
}
$this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);
$this->db->exec("set sql_mode = ''");
$this->db->exec("set names utf8mb4");
$this->db->exec("set time_zone='+8:00'");
}
/**
* 设置结果集方式
*
* @param string $_style
*/
public function setFetchStyle($_style)
{
$this->fetchStyle = $_style;
}
/**
* 替换数据表前缀
* @param $_sql
*
* @return mixed
*/
private function dealPrefix($_sql){
return str_replace($this->sqlPrefix,$this->prefix,$_sql);
}
private function _where($conditions){
$result = array( "_where" => " ","_bindParams" => array());
if(is_array($conditions) && !empty($conditions)){
$fieldss = array(); $sql = null; $join = array();
if(isset($conditions[0]) && $sql = $conditions[0]) unset($conditions[0]);
foreach( $conditions as $key => $condition ){
if(substr($key, 0, 1) != ":"){
unset($conditions[$key]);
$conditions[":".$key] = $condition;
}
$join[] = "`{$key}` = :{$key}";
}
if(!$sql) $sql = join(" AND ",$join);
$result["_where"] = " WHERE ". $sql;
$result["_bindParams"] = $conditions;
}elseif(!empty($conditions)){
$result["_where"] = " WHERE ". $conditions;
}
return $result;
}
private function _select($table, $fields = '*', $where = array(), $sort = null, $limit = null){
$sort = !empty($sort) ? ' ORDER BY '.$sort : '';
$fields = !empty($fields) ? $fields : '*';
if(is_array($fields)){
$fields = implode(',',$fields);
}
$conditions = $this->_where($where);
$sql = ' FROM pre_'.$table.$conditions["_where"];
if(is_array($limit)){
$limit = ' LIMIT '.$limit[0].','.$limit[1];
}elseif(!empty($limit)){
$limit = ' LIMIT '.$limit;
}else{
$limit = '';
}
return array('sql'=>'SELECT '. $fields . $sql . $sort . $limit, 'bind'=>$conditions["_bindParams"]);
}
/**
* 查询一条数据
* @param string $table
* @param string $fields
* @param array $where
* @param string $sort
* @param int $limit
*
* @return array
*/
public function find($table, $fields = '*', $where = array(), $sort = null, $limit = null){
$sql_arr = $this->_select($table, $fields, $where, $sort, $limit);
return $this->getRow($sql_arr['sql'], $sql_arr['bind']);
}
/**
* 查询全部数据
* @param string $table
* @param string $fields
* @param array $where
* @param string $sort
* @param int $limit
*
* @return array
*/
public function findAll($table, $fields = '*', $where = array(), $sort = null, $limit = null){
$sql_arr = $this->_select($table, $fields, $where, $sort, $limit);
return $this->getAll($sql_arr['sql'], $sql_arr['bind']);
}
/**
* 查询字段数据
* @param string $table
* @param string $fields
* @param array $where
* @param string $sort
*
* @return mixed
*/
public function findColumn($table, $fields, $where = array(), $sort = null){
$sql_arr = $this->_select($table, $fields, $where, $sort, 1);
return $this->getColumn($sql_arr['sql'], $sql_arr['bind']);
}
/**
* 插入数据
* @param string $table
* @param array $data
* @param bool $replace
*
* @return int
*/
public function insert($table, $data, $replace = false){
$values = array();
foreach ($data as $k=>$v){
$keys[] = "`{$k}`";
if ($v == 'NOW()' || $v == 'CURDATE()' || $v == 'CURTIME()') {
$marks[] = $v;
}elseif ($v === null || $v === false) {
$marks[] = 'NULL';
}else{
$values[":".$k] = $v;
$marks[] = ":".$k;
}
}
$rowCount = $this->exec(($replace?"REPLACE":"INSERT")." INTO pre_".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $marks).")", $values);
if($rowCount){
return $this->lastInsertId();
}else{
return false;
}
}
/**
* 更新数据
* @param string $table
* @param array $data
* @param array $where
*
* @return int
*/
public function update($table, $data, $where){
if(is_array($data) && !empty($data)){
$values = array();
foreach ($data as $k=>$v){
if($v == 'NOW()' || $v == 'CURDATE()' || $v == 'CURTIME()'){
$setstr[] = "`{$k}` = ".$v;
}elseif($v === null || $v === false){
$setstr[] = "`{$k}` = NULL";
}else{
$values[":M_UPDATE_".$k] = $v;
$setstr[] = "`{$k}` = :M_UPDATE_".$k;
}
}
$update = implode(', ', $setstr);
}elseif(!empty($data)){
$update = $data;
}else{
return false;
}
$conditions = $this->_where($where);
$rowCount = $this->exec("UPDATE pre_".$table." SET ".$update.$conditions["_where"], $conditions["_bindParams"] + $values);
return $rowCount;
}
/**
* 删除数据
* @param string $table
* @param array $where
*
* @return int
*/
public function delete($table, $where){
$conditions = $this->_where($where);
$rowCount = $this->exec("DELETE FROM pre_".$table.$conditions["_where"], $conditions["_bindParams"]);
return $rowCount;
}
/**
* 统计行数
* @param string $table
* @param array $where
*
* @return int
*/
public function count($table, $where){
$conditions = $this->_where($where);
$count = $this->getColumn("SELECT COUNT(*) FROM pre_".$table.$conditions["_where"], $conditions["_bindParams"]);
return $count;
}
/**
* 执行语句
* @param string $_sql
* @param array $_array
*
* @return int|bool
*/
public function exec($_sql, $_array = null)
{
$_sql = $this->dealPrefix($_sql);
if (is_array($_array)) {
$stmt = $this->db->prepare($_sql);
if($stmt) {
$result = $stmt->execute($_array);
if($result!==false){
return $result;
}else{
$this->errorInfo = $stmt->errorInfo();
return false;
}
}else{
$this->errorInfo = $this->db->errorInfo();
return false;
}
} else {
$result = $this->db->exec($_sql);
if($result!==false){
return $result;
}else{
$this->errorInfo = $this->db->errorInfo();
return false;
}
}
}
/**
* 获取PDOStatement
* @param string $_sql
* @param array $_array
*
* @return \PDOStatement
*/
public function query($_sql, $_array = null)
{
$_sql = $this->dealPrefix($_sql);
if (is_array($_array)) {
$stmt = $this->db->prepare($_sql);
if($stmt) {
if($stmt->execute($_array)){
return $stmt;
}else{
$this->errorInfo = $stmt->errorInfo();
return false;
}
}else{
$this->errorInfo = $this->db->errorInfo();
return false;
}
} else {
if($stmt = $this->db->query($_sql)){
return $stmt;
}else{
$this->errorInfo = $this->db->errorInfo();
return false;
}
}
}
/**
* 查询一条结果
*
* @param string $_sql string
* @param array $_array array
*
* @return mixed
*/
public function getRow($_sql, $_array = null)
{
$stmt = $this->query($_sql, $_array);
if($stmt) {
return $stmt->fetch($this->fetchStyle);
}else{
return false;
}
}
/**
* 获取所有结果
*
* @param string $_sql
* @param array $_array
*
* @return array
*/
public function getAll($_sql, $_array = null)
{
$stmt = $this->query($_sql, $_array);
if($stmt) {
return $stmt->fetchAll($this->fetchStyle);
}else{
return false;
}
}
/**
* 获取结果数
* @param string $_sql
* @param array $_array
*
* @return int
*/
public function getCount($_sql, $_array = null)
{
$stmt = $this->query($_sql, $_array);
if($stmt) {
return $stmt->rowCount();
}else{
return false;
}
}
/**
* 获取一个字段值
* @param string $_sql
* @param array $_array
*
* @return int
*/
public function getColumn($_sql, $_array = null)
{
$stmt = $this->query($_sql, $_array);
if($stmt) {
return $stmt->fetchColumn();
}else{
return false;
}
}
/**
* 返回最后插入行的ID
*
* @return int|\PDOStatement
*/
public function lastInsertId()
{
return $this->db->lastInsertId();
}
/**
* 返回错误信息
*
* @return string|\PDOStatement
*/
public function error()
{
$error = $this->errorInfo;
if($error){
return '['.$error[1].']'.$error[2];
}else{
return null;
}
}
//开启事务
public function beginTransaction()
{
return $this->db->beginTransaction();
}
//提交事务
public function commit()
{
return $this->db->commit();
}
//回滚事务
public function rollBack()
{
return $this->db->rollBack();
}
//事务
public function transaction($action){
if (is_callable($action))
{
$this->db->beginTransaction();
try {
$result = $action($this);
if ($result === false)
{
$this->db->rollBack();
}
else
{
$this->db->commit();
}
}
catch (\Exception $e) {
$this->db->rollBack();
throw $e;
}
return $result;
}
return false;
}
function __get($name)
{
return $this->$name;
}
function __destruct()
{
$this->db = null;
}
}
+241
View File
@@ -0,0 +1,241 @@
<?php
namespace lib;
use Exception;
class Plugin {
static public function getList(){
$dir = PLUGIN_ROOT;
$dirArray[] = NULL;
if (false != ($handle = opendir($dir))) {
$i = 0;
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != ".." && strpos($file, ".")===false) {
$dirArray[$i] = $file;
$i++;
}
}
closedir($handle);
}
return $dirArray;
}
static public function getConfig($name){
$filename = PLUGIN_ROOT.$name.'/'.$name.'_plugin.php';
$classname = '\\'.$name.'_plugin';
if(file_exists($filename)){
include $filename;
if (class_exists($classname, false) && property_exists($classname, 'info')) {
return $classname::$info;
}else{
return false;
}
}else{
return false;
}
}
static public function loadForPay($s){
global $DB,$conf,$order,$channel,$ordername;
if(preg_match('/^(.[a-zA-Z0-9]+)\/([0-9]+)\/$/',$s, $matchs)){
$func = $matchs[1];
$trade_no = $matchs[2];
$order = $DB->getRow("SELECT A.*,B.name typename,B.showname typeshowname FROM pre_order A left join pre_type B on A.type=B.id WHERE trade_no=:trade_no limit 1", [':trade_no'=>$trade_no]);
$userrow = $DB->find('user', 'gid,ordername,channelinfo', ['uid'=>$order['uid']]);
if (!$order) {
$channelinfo = $userrow?$userrow['channelinfo']:null;
$channel = \lib\Channel::get($trade_no, $channelinfo);
if(!$channel) throw new Exception('该订单号不存在,请返回来源地重新发起请求!');
$trade_no = null;
}else{
$channelinfo = $userrow?$userrow['channelinfo']:null;
$channel = $order['subchannel'] > 0 ? \lib\Channel::getSub($order['subchannel']) : \lib\Channel::get($order['channel'], $channelinfo);
if(!$channel) throw new Exception('当前支付通道信息不存在');
$channel['apptype'] = explode(',',$channel['apptype']);
if(!empty($userrow['ordername']))$conf['ordername']=$userrow['ordername'];
$ordername = !empty($conf['ordername'])?ordername_replace($conf['ordername'],$order['name'],$order['uid'],$trade_no,$order['out_trade_no']):$order['name'];
$order['plugin'] = $channel['plugin'];
}
$groupconfig = getGroupConfig($userrow['gid']);
$conf = array_merge($conf, $groupconfig);
$result = self::loadClass($channel['plugin'], $func, $trade_no);
if($func == 'submit') {
$result['submit'] = true;
}
return $result;
}else{
throw new Exception('URL参数不符合规范');
}
}
static public function loadForSubmit($plugin, $trade_no, $ismapi=false){
global $DB,$conf,$order,$channel,$ordername,$userrow;
if(preg_match('/^(.[a-zA-Z0-9]+)$/',$plugin) && preg_match('/^(.[0-9]+)$/',$trade_no)){
$func = 'submit';
if($ismapi) $func = 'mapi';
$channelinfo = $userrow?$userrow['channelinfo']:null;
$channel = $order['subchannel'] > 0 ? \lib\Channel::getSub($order['subchannel']) : \lib\Channel::get($order['channel'], $channelinfo);
if(!$channel)throw new Exception('当前支付通道信息不存在');
$channel['apptype'] = explode(',',$channel['apptype']);
if(!empty($userrow['ordername']))$conf['ordername']=$userrow['ordername'];
$ordername = !empty($conf['ordername'])?ordername_replace($conf['ordername'],$order['name'],$order['uid'],$trade_no,$order['out_trade_no']):$order['name'];
return self::loadClass($plugin, $func, $trade_no);
}else{
throw new Exception('URL参数不符合规范');
}
}
static public function loadClass($plugin, $func, $trade_no){
$filename = PLUGIN_ROOT.$plugin.'/'.$plugin.'_plugin.php';
$classname = '\\'.$plugin.'_plugin';
if (file_exists($filename)) {
if(!defined("IN_PLUGIN")) define("IN_PLUGIN", true);
define("PAY_ROOT", PLUGIN_ROOT.$plugin.'/');
define("TRADE_NO", $trade_no);
include $filename;
if (class_exists($classname, false) && method_exists($classname, $func)) {
return $classname::$func();
} else {
if($func == 'mapi' && class_exists($classname, false) && method_exists($classname, 'submit')){
global $siteurl;
return ['type'=>'jump','url'=>$siteurl.'pay/submit/'.TRADE_NO.'/'];
}else{
throw new Exception('插件方法不存在:'.$func);
}
}
}else{
throw new Exception('Pay file not found');
}
}
static public function exists($name){
$filename = PLUGIN_ROOT.$name.'/'.$name.'_plugin.php';
if(file_exists($filename)){
return true;
}else{
return false;
}
}
static public function isrefund($name){
$filename = PLUGIN_ROOT.$name.'/'.$name.'_plugin.php';
$classname = '\\'.$name.'_plugin';
if(file_exists($filename)){
include $filename;
if (class_exists($classname, false) && method_exists($classname, 'refund')) {
return true;
}else{
return false;
}
}else{
return false;
}
}
static public function refund($refund_no, $trade_no, $money, &$message){
global $order,$channel,$DB;
if(!preg_match('/^(.[0-9]+)$/',$trade_no))return false;
$channel = $order['subchannel'] > 0 ? \lib\Channel::getSub($order['subchannel']) : \lib\Channel::get($order['channel'], $DB->findColumn('user', 'channelinfo', ['uid'=>$order['uid']]));
if(!$channel){
$message = '当前支付通道信息不存在';
return false;
}
$order['refund_no'] = $refund_no;
$order['refundmoney'] = $money;
$filename = PLUGIN_ROOT.$channel['plugin'].'/'.$channel['plugin'].'_plugin.php';
$classname = '\\'.$channel['plugin'].'_plugin';
$func = 'refund';
if($order['combine'] == 1) $func = 'refund_combine';
if(file_exists($filename)){
include $filename;
if (class_exists($classname, false) && method_exists($classname, $func)) {
if(!defined("IN_PLUGIN")) define("IN_PLUGIN", true);
define("PAY_ROOT", PLUGIN_ROOT.$channel['plugin'].'/');
define("TRADE_NO", $trade_no);
$result = $classname::$func($order);
if($result && $result['code']==0){
return true;
}else{
$message = $result['msg'];
return false;
}
}else{
$message = '当前支付通道不支持API退款';
return false;
}
}else{
$message = '支付插件不存在';
return false;
}
}
static public function loadForAdmin($func){
global $channel;
$filename = PLUGIN_ROOT.$channel['plugin'].'/'.$channel['plugin'].'_plugin.php';
$classname = '\\'.$channel['plugin'].'_plugin';
if(file_exists($filename)){
include_once $filename;
if (class_exists($classname, false) && method_exists($classname, $func)) {
if(!defined("IN_PLUGIN")) define("IN_PLUGIN", true);
define("PAY_ROOT", PLUGIN_ROOT.$channel['plugin'].'/');
return $classname::$func($channel);
}else{
throw new Exception('插件方法不存在:'.$func);
}
}else{
throw new Exception('支付插件不存在');
}
}
static public function call($func, $channel, $bizParam = null){
$filename = PLUGIN_ROOT.$channel['plugin'].'/'.$channel['plugin'].'_plugin.php';
$classname = '\\'.$channel['plugin'].'_plugin';
if(file_exists($filename)){
include_once $filename;
if (class_exists($classname, false) && method_exists($classname, $func)) {
if($bizParam){
$result = $classname::$func($channel, $bizParam);
}else{
$result = $classname::$func($channel);
}
return $result;
}else{
return ['code'=>-1, 'msg'=>'插件方法不存在:'.$func];
}
}else{
return ['code'=>-1, 'msg'=>'支付插件不存在'];
}
}
static public function updateAll(){
global $DB;
$DB->exec("TRUNCATE TABLE pre_plugin");
$list = self::getList();
foreach($list as $name){
if($config = self::getConfig($name)){
if($config['name']!=$name)continue;
$DB->insert('plugin',['name'=>$config['name'], 'showname'=>$config['showname'], 'author'=>$config['author'], 'link'=>$config['link'], 'types'=>implode(',',$config['types']), 'transtypes'=>$config['transtypes']?implode(',',$config['transtypes']):null]);
}
}
return true;
}
static public function get($name){
global $DB;
$result = $DB->getRow("SELECT * FROM pre_plugin WHERE name=:name", [':name'=>$name]);
return $result;
}
static public function getAll(){
global $DB;
$result = $DB->getAll("SELECT * FROM pre_plugin ORDER BY name ASC");
return $result;
}
}
+109
View File
@@ -0,0 +1,109 @@
<?php
namespace lib\ProfitSharing;
require_once PLUGIN_ROOT . 'adapay/inc/Build.class.php';
use Exception;
class Adapay implements IProfitSharing
{
static $paytype = 'adapay';
private $channel;
private $service;
function __construct($channel){
$this->channel = $channel;
$pay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$this->service = \AdaPay::config($pay_config);
}
//请求分账
public function submit($trade_no, $api_trade_no, $account, $name, $money){
global $DB;
$order_money = $DB->findColumn('order', 'realmoney', ['trade_no'=>$trade_no]);
if(strpos($account, '|')){
$accounts = explode('|', $account);
$psorder = CommUtil::getOrder($trade_no);
$rates = explode('|', $psorder['rate']);
$div_members = [];
$allmoney = 0;
foreach($accounts as $i=>$account){
$rate = isset($rates[$i]) ? $rates[$i] : $rates[0];
$money = round($order_money * $rate / 100, 2);
$div_members[] = ['member_id'=>$account, 'amount' => sprintf('%.2f' , $money), 'fee_flag'=>$i==0?'Y':'N'];
$allmoney += $money;
}
if($order_money > $allmoney){
$psmoney2 = round($order_money-$allmoney, 2);
$div_members[] = ['member_id'=>'0', 'amount' => sprintf('%.2f' , $psmoney2), 'fee_flag'=>'N'];
}
}else{
$psmoney2 = round($order_money-$money, 2);
$div_members = [];
$div_members[] = ['member_id'=>$account, 'amount' => sprintf('%.2f' , $money), 'fee_flag'=>'Y'];
if($psmoney2 > 0){
$div_members[] = ['member_id'=>'0', 'amount' => sprintf('%.2f' , $psmoney2), 'fee_flag'=>'N'];
}
}
$params = [
'payment_id' => $api_trade_no,
'order_no' => date("YmdHis").rand(11111,99999),
'confirm_amt' => $order_money,
'div_members' => $div_members,
];
try{
$result = $this->service->createPaymentConfirm($params);
return ['code'=>1, 'msg'=>'分账成功', 'settle_no'=>$result['id']];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//查询分账结果
public function query($trade_no, $api_trade_no, $settle_no){
try{
$result = $this->service->queryPaymentConfirm($settle_no);
return ['code'=>0, 'status'=>1];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//解冻剩余资金
public function unfreeeze($trade_no, $api_trade_no){
global $DB;
$order_money = $DB->findColumn('order', 'realmoney', ['trade_no'=>$trade_no]);
$params = [
'payment_id' => $api_trade_no,
'order_no' => date("YmdHis").rand(11111,99999),
'reverse_amt' => $order_money,
];
try{
$result = $this->service->createPaymentReverse($params);
return ['code'=>0, 'msg'=>'解冻剩余资金成功', 'settle_no'=>$result['id']];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//分账回退
public function return($trade_no, $api_trade_no, $account, $money){
return ['code'=>-1,'msg'=>'不支持当前操作'];
}
//添加分账接收方
public function addReceiver($account, $name = null){
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
}
//删除分账接收方
public function deleteReceiver($account){
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
}
}
+159
View File
@@ -0,0 +1,159 @@
<?php
namespace lib\ProfitSharing;
use Exception;
class Alipay implements IProfitSharing
{
static $paytype = 'alipay';
private $channel;
private $service;
function __construct($channel){
$this->channel = $channel;
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$this->service = new \Alipay\AlipaySettleService($alipay_config);
}
//请求分账
public function submit($trade_no, $api_trade_no, $account, $name, $money){
if(strpos($account, '|')){
global $DB;
$accounts = explode('|', $account);
$psorder = CommUtil::getOrder($trade_no);
$rates = explode('|', $psorder['rate']);
$order_money = $DB->findColumn('order', 'realmoney', ['trade_no'=>$trade_no]);
$receivers = [];
foreach($accounts as $i=>$account){
$rate = isset($rates[$i]) ? $rates[$i] : $rates[0];
$money = round($order_money * $rate / 100, 2);
$type = self::get_alipay_account_type($account);
$receivers[] = [
'trans_in_type' => $type,
'trans_in' => $account,
'amount' => $money
];
}
$bizContent = array(
'out_request_no' => date("YmdHis").rand(11111,99999),
'trade_no' => $api_trade_no,
'royalty_parameters' => $receivers,
'extend_params' => [
'royalty_finish' => 'true'
]
);
try{
$result = $this->service->aopExecute('alipay.trade.order.settle', $bizContent);
return ['code'=>1, 'msg'=>'分账成功', 'settle_no'=>$result['settle_no']];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
$type = self::get_alipay_account_type($account);
try{
$result = $this->service->order_settle($api_trade_no, $type, $account, $money);
return ['code'=>1, 'msg'=>'分账成功', 'settle_no'=>$result['settle_no']];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//查询分账结果
public function query($trade_no, $api_trade_no, $settle_no){
try{
$result = $this->service->order_settle_query($settle_no);
$receiver = $result['royalty_detail_list'][0];
if($receiver['state'] == 'SUCCESS'){
return ['code'=>0, 'status'=>1];
}elseif($receiver['state'] == 'FAIL'){
return ['code'=>0, 'status'=>2, 'reason'=>'['.$receiver['error_code'].']'.$receiver['error_desc']];
}else{
return ['code'=>0, 'status'=>0];
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//解冻剩余资金
public function unfreeeze($trade_no, $api_trade_no){
try{
$this->service->order_settle_unfreeze($api_trade_no);
return ['code'=>0, 'msg'=>'解冻剩余资金成功'];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//分账回退
public function return($trade_no, $api_trade_no, $account, $money){
$type = self::get_alipay_account_type($account);
try{
$this->service->order_settle_refund($api_trade_no, $type, $account, $money);
return ['code'=>0, 'msg'=>'退分账成功'];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//添加分账接收方
public function addReceiver($account, $name = null){
if(strpos($account, '|')){
$accounts = explode('|', $account);
$names = explode('|', $name);
foreach($accounts as $i => $account){
$type = self::get_alipay_account_type($account);
try{
$this->service->relation_bind($type, $account, $name ? $names[$i] : null);
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
}
$type = self::get_alipay_account_type($account);
try{
$this->service->relation_bind($type, $account, $name);
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//删除分账接收方
public function deleteReceiver($account){
if(strpos($account, '|')){
$accounts = explode('|', $account);
foreach($accounts as $account){
$type = self::get_alipay_account_type($account);
try{
$this->service->relation_unbind($type, $account);
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
}
$type = self::get_alipay_account_type($account);
try{
$this->service->relation_unbind($type, $account);
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
private static function get_alipay_account_type($account){
if(is_numeric($account) && substr($account,0,4)=='2088' && strlen($account)==16)$type = 'userId';
else $type = 'loginName';
return $type;
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace lib\ProfitSharing;
use Exception;
class Chinaums implements IProfitSharing
{
static $paytype = 'chinaums';
private $channel;
private $service;
function __construct($channel){
$this->channel = $channel;
}
//请求分账
public function submit($trade_no, $api_trade_no, $account, $name, $money){
}
//查询分账结果
public function query($trade_no, $api_trade_no, $settle_no){
}
//解冻剩余资金
public function unfreeeze($trade_no, $api_trade_no){
}
//分账回退
public function return($trade_no, $api_trade_no, $account, $money){
}
//添加分账接收方
public function addReceiver($account, $name = null){
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
}
//删除分账接收方
public function deleteReceiver($account){
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
}
}
+104
View File
@@ -0,0 +1,104 @@
<?php
namespace lib\ProfitSharing;
use Exception;
class CommUtil
{
public static $plugins = ['alipay','alipaysl','alipayd','wxpayn','wxpaynp','yeepay','yseqt','chinaums','dinpay','adapay'];
public static $no_order_plugins = ['chinaums','dinpay'];
public static function getModel($channel){
if($channel['plugin'] == 'alipay' || $channel['plugin'] == 'alipaysl' || $channel['plugin'] == 'alipayd'){
return new Alipay($channel);
}elseif($channel['plugin'] == 'wxpayn' || $channel['plugin'] == 'wxpaynp'){
return new Wxpay($channel);
}elseif($channel['plugin'] == 'yeepay'){
return new Yeepay($channel);
}elseif($channel['plugin'] == 'yseqt'){
return new Yseqt($channel);
}elseif($channel['plugin'] == 'chinaums'){
return new Chinaums($channel);
}elseif($channel['plugin'] == 'dinpay'){
return new Dinpay($channel);
}elseif($channel['plugin'] == 'adapay'){
return new Adapay($channel);
}
return false;
}
public static function getReceiver($id){
global $DB;
return $DB->find('psreceiver', '*', ['id'=>$id]);
}
public static function getOrder($trade_no){
global $DB;
return $DB->getRow("SELECT A.*,B.channel,B.account,B.name,B.rate FROM pre_psorder A LEFT JOIN pre_psreceiver B ON A.rid=B.id WHERE A.trade_no=:trade_no", [':trade_no'=>$trade_no]);
}
//订单分账定时任务
public static function task(){
global $DB;
$limit = 10; //每次查询分账的订单数量
$list = $DB->getAll("SELECT A.*,B.channel,B.account,B.name,B.uid psuid,C.uid,C.subchannel FROM pre_psorder A INNER JOIN pre_psreceiver B ON B.id=A.rid LEFT JOIN pre_order C ON C.trade_no=A.trade_no WHERE A.status=1 ORDER BY A.id ASC LIMIT {$limit}");
foreach($list as $srow){
self::process_item($srow);
}
$limit = 10; //每次提交分账的订单数量
$list = $DB->getAll("SELECT A.*,B.channel,B.account,B.name,B.uid psuid,C.uid,C.subchannel FROM pre_psorder A INNER JOIN pre_psreceiver B ON B.id=A.rid LEFT JOIN pre_order C ON C.trade_no=A.trade_no WHERE A.status=0 AND (A.addtime<=DATE_SUB(NOW(), INTERVAL 60 SECOND) AND A.delay=0 OR A.addtime<=DATE_SUB(NOW(), INTERVAL 24 HOUR) AND A.delay=1) ORDER BY A.id ASC LIMIT {$limit}");
foreach($list as $srow){
self::process_item($srow);
}
}
//处理一个订单分账任务
public static function process_item($row){
global $DB;
$id = $row['id'];
$channel = $row['subchannel'] > 0 ? \lib\Channel::getSub($row['subchannel']) : \lib\Channel::get($row['channel'], $row['uid']?$DB->findColumn('user', 'channelinfo', ['uid'=>$row['uid']]):null);
if(!$channel) return;
$model = self::getModel($channel);
// status:0-待分账,1-已提交,2-成功,3-失败
if($row['status']==0){
if($row['money'] == 0){
$DB->update('psorder', ['status'=>3,'result'=>'分账金额为0'], ['id'=>$id]);
echo $row['trade_no'].' 分账金额为0<br/>';
return;
}
$result = $model->submit($row['trade_no'], $row['api_trade_no'], $row['account'], $row['name'], $row['money']);
if($result['code'] == 0){
$DB->update('psorder', ['status'=>1,'settle_no'=>$result['settle_no']], ['id'=>$id]);
}elseif($result['code'] == 1){
$DB->update('psorder', ['status'=>2,'settle_no'=>$result['settle_no']], ['id'=>$id]);
if(!empty($row['psuid']) && $channel['mode']==0){
changeUserMoney($row['psuid'], $row['money'], false, '订单分账', $row['trade_no']);
}
}elseif($result['code'] == -1){
$DB->update('psorder', ['status'=>3,'result'=>$result['msg']], ['id'=>$id]);
}
echo $row['trade_no'].' '.$result['msg'].'<br/>';
}elseif($row['status']==1){
$result = $model->query($row['trade_no'], $row['api_trade_no'], $row['settle_no']);
if($result['code']==0){
if($result['status']==1){
$DB->update('psorder', ['status'=>2], ['id'=>$id]);
if(!empty($row['psuid']) && $channel['mode']==0){
changeUserMoney($row['psuid'], $row['money'], false, '订单分账', $row['trade_no']);
}
$result = '分账成功';
}elseif($result['status']==2){
$DB->update('psorder', ['status'=>3,'result'=>$result['reason']], ['id'=>$id]);
$result = '分账失败:'.$result['reason'];
}else{
$result = '正在分账';
}
echo $row['trade_no'].' '.$result.'<br/>';
}else{
echo $row['trade_no'].' 查询失败:'.$result['msg'].'<br/>';
}
}
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace lib\ProfitSharing;
use Exception;
class Dinpay implements IProfitSharing
{
static $paytype = 'dinpay';
private $channel;
private $service;
function __construct($channel){
$this->channel = $channel;
}
//请求分账
public function submit($trade_no, $api_trade_no, $account, $name, $money){
}
//查询分账结果
public function query($trade_no, $api_trade_no, $settle_no){
}
//解冻剩余资金
public function unfreeeze($trade_no, $api_trade_no){
}
//分账回退
public function return($trade_no, $api_trade_no, $account, $money){
}
//添加分账接收方
public function addReceiver($account, $name = null){
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
}
//删除分账接收方
public function deleteReceiver($account){
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
}
}
@@ -0,0 +1,25 @@
<?php
namespace lib\ProfitSharing;
interface IProfitSharing
{
//请求分账
function submit($trade_no, $api_trade_no, $account, $name, $money);
//查询分账结果
function query($trade_no, $api_trade_no, $settle_no);
//解冻剩余资金
function unfreeeze($trade_no, $api_trade_no);
//分账回退
function return($trade_no, $api_trade_no, $account, $money);
//添加分账接收方
function addReceiver($account, $name = null);
//删除分账接收方
function deleteReceiver($account);
}
+219
View File
@@ -0,0 +1,219 @@
<?php
namespace lib\ProfitSharing;
use Exception;
class Wxpay implements IProfitSharing
{
static $paytype = 'wxpay';
private $channel;
private $service;
private $ecommerce;
function __construct($channel){
$this->channel = $channel;
$wechatpay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$this->ecommerce = $wechatpay_config['ecommerce'];
$this->service = new \WeChatPay\V3\ProfitsharingService($wechatpay_config);
}
//请求分账
public function submit($trade_no, $api_trade_no, $account, $name, $money){
if(strpos($account, '|')){
global $DB;
$accounts = explode('|', $account);
$psorder = CommUtil::getOrder($trade_no);
$rates = explode('|', $psorder['rate']);
$order_money = $DB->findColumn('order', 'realmoney', ['trade_no'=>$trade_no]);
$receivers = [];
foreach($accounts as $i=>$account){
$rate = isset($rates[$i]) ? $rates[$i] : $rates[0];
$money = round($order_money * $rate / 100, 2);
$type = self::get_wxpay_account_type($account);
if($this->ecommerce){
$receivers[] = [
'type' => $type,
'receiver_account' => $account,
'amount' => intval(round($money*100)),
'description' => '订单分账'
];
}else{
$receivers[] = [
'type' => $type,
'account' => $account,
'amount' => intval(round($money*100)),
'description' => '订单分账'
];
}
}
if($this->ecommerce){
$param = [
'transaction_id' => $api_trade_no,
'out_order_no' => $trade_no,
'receivers' => $receivers,
'finish' => true,
];
}else{
$param = [
'transaction_id' => $api_trade_no,
'out_order_no' => $trade_no,
'receivers' => $receivers,
'unfreeze_unsplit' => true,
];
}
try{
$result = $this->service->submit($param);
return ['code'=>0, 'msg'=>'请求分账成功', 'settle_no'=>$result['order_id']];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
$type = self::get_wxpay_account_type($account);
if($this->ecommerce){
$param = [
'transaction_id' => $api_trade_no,
'out_order_no' => $trade_no,
'receivers' => [
[
'type' => $type,
'receiver_account' => $account,
'amount' => intval(round($money*100)),
'description' => '订单分账'
]
],
'finish' => true,
];
}else{
$param = [
'transaction_id' => $api_trade_no,
'out_order_no' => $trade_no,
'receivers' => [
[
'type' => $type,
'account' => $account,
'amount' => intval(round($money*100)),
'description' => '订单分账'
]
],
'unfreeze_unsplit' => true,
];
}
try{
$result = $this->service->submit($param);
return ['code'=>0, 'msg'=>'请求分账成功', 'settle_no'=>$result['order_id']];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//查询分账结果
public function query($trade_no, $api_trade_no, $settle_no){
$reason_desc = ['ACCOUNT_ABNORMAL'=>'分账接收账户异常', 'NO_RELATION'=>'分账关系已解除', 'RECEIVER_HIGH_RISK'=>'高风险接收方', 'RECEIVER_REAL_NAME_NOT_VERIFIED'=>'接收方未实名', 'NO_AUTH'=>'分账权限已解除', 'RECEIVER_RECEIPT_LIMIT'=>'接收方已达收款限额', 'PAYER_ACCOUNT_ABNORMAL'=>'分出方账户异常', 'INVALID_REQUEST'=>'描述参数设置失败'];
try{
$result = $this->service->query($trade_no, $api_trade_no);
if(isset($result['state']) && $result['state'] == 'FINISHED' || isset($result['status']) && $result['status'] == 'FINISHED'){
$receiver = $result['receivers'][0];
if($receiver['result'] == 'SUCCESS'){
return ['code'=>0, 'status'=>1];
}elseif($receiver['result'] == 'CLOSED'){
return ['code'=>0, 'status'=>2, 'reason'=>'['.$receiver['fail_reason'].']'.$reason_desc[$receiver['fail_reason']]];
}else{
return ['code'=>0, 'status'=>0];
}
}else{
return ['code'=>0, 'status'=>0];
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//解冻剩余资金
public function unfreeeze($trade_no, $api_trade_no){
try{
$this->service->unfreeze($trade_no, $api_trade_no);
return ['code'=>0, 'msg'=>'解冻剩余资金成功'];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//分账回退
public function return($trade_no, $api_trade_no, $account, $money){
$type = self::get_wxpay_account_type($account);
if($type == 'MERCHANT_ID'){
$params = [
'out_order_no' => $trade_no,
'out_return_no' => 'REF'.$trade_no,
'return_mchid' => $account,
'amount' => intval(round($money*100)),
'description' => '分账回退'
];
try{
$this->service->return($params);
return ['code'=>0, 'msg'=>'分账回退成功'];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}else{
return ['code'=>-1,'msg'=>'分账到个人账户不支持回退'];
}
}
//添加分账接收方
public function addReceiver($account, $name = null){
if(strpos($account, '|')){
$accounts = explode('|', $account);
$names = explode('|', $name);
foreach($accounts as $i => $account){
$type = self::get_wxpay_account_type($account);
try{
$this->service->addReceiver($type, $account, $name ? $names[$i] : null);
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
}
$type = self::get_wxpay_account_type($account);
try{
$this->service->addReceiver($type, $account, $name);
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//删除分账接收方
public function deleteReceiver($account){
if(strpos($account, '|')){
$accounts = explode('|', $account);
foreach($accounts as $account){
$type = self::get_wxpay_account_type($account);
try{
$this->service->deleteReceiver($type, $account);
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
}
$type = self::get_wxpay_account_type($account);
try{
$this->service->deleteReceiver($type, $account);
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
private static function get_wxpay_account_type($account){
if(is_numeric($account))$type = 'MERCHANT_ID';
else $type = 'PERSONAL_OPENID';
return $type;
}
}
+137
View File
@@ -0,0 +1,137 @@
<?php
namespace lib\ProfitSharing;
require(PLUGIN_ROOT.'yeepay/inc/YopClient.php');
use Exception;
class Yeepay implements IProfitSharing
{
static $paytype = 'yeepay';
private $channel;
private $service;
function __construct($channel){
$this->channel = $channel;
$this->service = new \Yeepay\YopClient($channel['appkey'], $channel['appsecret']);
}
//请求分账
public function submit($trade_no, $api_trade_no, $account, $name, $money){
$divideDetail = [
[
'ledgerNo' => $account,
'amount' => $money,
'ledgerType' => 'MERCHANT2MERCHANT',
]
];
$params = [
'parentMerchantNo' => $this->channel['appid'],
'merchantNo' => empty($this->channel['appmchid'])?$this->channel['appid']:$this->channel['appmchid'],
'orderId' => $trade_no,
'uniqueOrderNo' => $api_trade_no,
'divideRequestId' => 'F'.$trade_no,
'divideDetail' => json_encode($divideDetail),
'isUnfreezeResidualAmount' => 'TRUE',
];
try{
$result = $this->service->post('/rest/v1.0/divide/apply', $params);
if($result['code'] == 'OPR00000'){
if($result['status'] == 'SUCCESS'){
return ['code'=>1, 'msg'=>'分账成功', 'settle_no'=>$result['divideRequestId']];
}else{
return ['code'=>0, 'msg'=>'请求分账成功', 'settle_no'=>$result['divideRequestId']];
}
}else{
throw new Exception('['.$result['code'].']'.$result['message']);
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//查询分账结果
public function query($trade_no, $api_trade_no, $settle_no){
$params = [
'parentMerchantNo' => $this->channel['appid'],
'merchantNo' => empty($this->channel['appmchid'])?$this->channel['appid']:$this->channel['appmchid'],
'divideRequestId' => $settle_no,
'orderId' => $trade_no,
'uniqueOrderNo' => $api_trade_no,
];
try{
$result = $this->service->get('/rest/v1.0/divide/query', $params);
if($result['code'] == 'OPR00000'){
if($result['status'] == 'SUCCESS'){
return ['code'=>0, 'status'=>1];
}elseif($result['status'] == 'FAIL'){
return ['code'=>0, 'status'=>2, 'reason'=>$result['message']];
}else{
return ['code'=>0, 'status'=>0];
}
}else{
throw new Exception('['.$result['code'].']'.$result['message']);
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//解冻剩余资金
public function unfreeeze($trade_no, $api_trade_no){
$params = [
'parentMerchantNo' => $this->channel['appid'],
'merchantNo' => empty($this->channel['appmchid'])?$this->channel['appid']:$this->channel['appmchid'],
'divideRequestId' => 'C'.$trade_no,
'orderId' => $trade_no,
'uniqueOrderNo' => $api_trade_no,
];
try{
$result = $this->service->post('/rest/v1.0/divide/complete', $params);
if($result['code'] == 'OPR00000'){
return ['code'=>0, 'msg'=>'解冻剩余资金成功'];
}else{
throw new Exception('['.$result['code'].']'.$result['message']);
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//分账回退
public function return($trade_no, $api_trade_no, $account, $money){
return ['code'=>-1, 'msg'=>'暂不支持分账回退'];
$params = [
'parentMerchantNo' => $this->channel['appid'],
'merchantNo' => empty($this->channel['appmchid'])?$this->channel['appid']:$this->channel['appmchid'],
'divideBackRequestId' => 'B'.$trade_no,
'divideRequestId' => $settle_no,
'orderId' => $trade_no,
'uniqueOrderNo' => $api_trade_no,
'divideBackDetail' => '',
];
try{
$result = $this->service->post('/rest/v1.0/divide/back', $params);
if($result['code'] == 'OPR00000'){
return ['code'=>0, 'msg'=>'退分账成功'];
}else{
throw new Exception('['.$result['code'].']'.$result['message']);
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//添加分账接收方
public function addReceiver($account, $name = null){
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
}
//删除分账接收方
public function deleteReceiver($account){
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
}
}
+145
View File
@@ -0,0 +1,145 @@
<?php
namespace lib\ProfitSharing;
require(PLUGIN_ROOT.'yseqt/inc/YseqtClient.php');
use Exception;
class Yseqt implements IProfitSharing
{
static $paytype = 'yseqt';
private $channel;
private $service;
function __construct($channel){
$this->channel = $channel;
$this->service = new \YseqtClient($channel['appid'], $channel['appkey']);
}
//请求分账
public function submit($trade_no, $api_trade_no, $account, $name, $money){
global $DB;
$order_money = $DB->findColumn('order', 'realmoney', ['trade_no'=>$trade_no]);
$divisionList = [
[
'divisionMercId' => $account,
'isChargeFee' => 'N',
'divAmount' => $money,
],
[
'divisionMercId' => $this->channel['appmchid'],
'isChargeFee' => 'Y',
'divAmount' => round($order_money-$money, 2),
]
];
$requestNo = date('YmdHis').rand(1000,9999);
$params = [
'requestNo' => $requestNo,
'payeeMerchantNo' => $this->channel['appmchid'],
'origRequestNo' => $trade_no,
'amount' => $order_money,
'isDivision' => 'Y',
'divisionMode' => '02',
'divisionList' => $divisionList,
];
try{
$result = $this->service->execute('divisionRegister', $params);
if($result['subCode'] == 'COM000'){
if($result['state'] == 'SPLIT_SUCCESS'){
return ['code'=>1, 'msg'=>'预分账成功', 'settle_no'=>$result['requestNo']];
}elseif($result['state'] == 'SUCCESS'){
return ['code'=>1, 'msg'=>'分账成功', 'settle_no'=>$result['requestNo']];
}else{
return ['code'=>0, 'msg'=>'受理成功', 'settle_no'=>$result['requestNo']];
}
}else{
throw new Exception($result['subMsg']);
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//查询分账结果
public function query($trade_no, $api_trade_no, $settle_no){
$params = [
'origRequestNo' => $trade_no,
];
try{
$result = $this->service->execute('divisionQuery', $params);
if($result['subCode'] == 'COM000'){
if($result['state'] == 'SPLIT_SUCCESS' || $result['state'] == 'SUCCESS'){
return ['code'=>0, 'status'=>1];
}elseif($result['state'] == 'FAILED'){
return ['code'=>0, 'status'=>2, 'reason'=>$result['note']];
}else{
return ['code'=>0, 'status'=>0];
}
}else{
throw new Exception($result['subMsg']);
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//解冻剩余资金
public function unfreeeze($trade_no, $api_trade_no){
global $DB;
$requestNo = date('YmdHis').rand(1000,9999);
$order_money = $DB->findColumn('order', 'realmoney', ['trade_no'=>$trade_no]);
$params = [
'requestNo' => $requestNo,
'payeeMerchantNo' => $this->channel['appmchid'],
'origRequestNo' => $trade_no,
'amount' => $order_money,
'isDivision' => 'N',
'divisionMode' => '02',
];
try{
$result = $this->service->execute('divisionRegister', $params);
if($result['subCode'] == 'COM000'){
return ['code'=>0, 'msg'=>'解冻剩余资金成功'];
}else{
throw new Exception($result['subMsg']);
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//分账回退
public function return($trade_no, $api_trade_no, $account, $money){
$requestNo = date('YmdHis').rand(1000,9999);
$params = [
'requestNo' => $requestNo,
'payeeMerchantNo' => $this->channel['appmchid'],
'origRequestNo' => $trade_no,
'divisionMercId' => $account,
'amount' => $money,
];
try{
$result = $this->service->execute('divisionBack', $params);
if($result['subCode'] == 'COM000'){
return ['code'=>0, 'msg'=>'退分账成功'];
}else{
throw new Exception($result['subMsg']);
}
} catch (Exception $e) {
return ['code'=>-1, 'msg'=>$e->getMessage()];
}
}
//添加分账接收方
public function addReceiver($account, $name = null){
return ['code'=>0, 'msg'=>'添加分账接收方成功'];
}
//删除分账接收方
public function deleteReceiver($account){
return ['code'=>0, 'msg'=>'删除分账接收方成功'];
}
}
+124
View File
@@ -0,0 +1,124 @@
<?php
namespace lib;
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
/*
* @brief QC类,api外部对象,调用接口全部依赖于此对象
* */
class QC{
const VERSION = "2.0";
const GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize";
const GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
const GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me";
private $appid;
private $appkey;
private $callback;
function __construct($QC_config){
$this->appid = $QC_config["appid"];
$this->appkey = $QC_config["appkey"];
$this->callback = $QC_config['callback'];
}
public function qq_login($is_geturl = false){
$state = md5(uniqid(rand(), TRUE));
$_SESSION['Oauth_state'] = $state;
//-------构造请求参数列表
$keysArr = array(
"response_type" => "code",
"client_id" => $this->appid,
"redirect_uri" => $this->callback,
"state" => $state
);
$login_url = self::GET_AUTH_CODE_URL.'?'.http_build_query($keysArr);
if($is_geturl){
return $login_url;
}
header("Location: $login_url");
}
public function qq_callback(){
if($_GET['state'] != $_SESSION['Oauth_state']){
sysmsg("<h2>The state does not match. You may be a victim of CSRF.</h2>");
}
//-------请求参数列表
$keysArr = array(
"grant_type" => "authorization_code",
"client_id" => $this->appid,
"redirect_uri" => $this->callback,
"client_secret" => $this->appkey,
"code" => $_GET['code']
);
//------构造请求access_token的url
$token_url = self::GET_ACCESS_TOKEN_URL.'?'.http_build_query($keysArr);
$response = $this->get_curl($token_url);
if(strpos($response, "callback") !== false){
$lpos = strpos($response, "(");
$rpos = strrpos($response, ")");
$response = substr($response, $lpos + 1, $rpos - $lpos -1);
$msg = json_decode($response);
if(isset($msg->error)){
sysmsg('<h3>error:</h3>'.$msg->error.'<h3>msg :</h3>'.$msg->error_description);
}
}
$params = array();
parse_str($response, $params);
return $params["access_token"];
}
public function get_openid($access_token){
//-------请求参数列表
$keysArr = array(
"access_token" => $access_token
);
$graph_url = self::GET_OPENID_URL.'?'.http_build_query($keysArr);
$response = $this->get_curl($graph_url);
//--------检测错误是否发生
if(strpos($response, "callback") !== false){
$lpos = strpos($response, "(");
$rpos = strrpos($response, ")");
$response = substr($response, $lpos + 1, $rpos - $lpos -1);
}
$user = json_decode($response);
if(isset($user->error)){
sysmsg('<h3>error:</h3>'.$user->error.'<h3>msg :</h3>'.$user->error_description);
}
//------记录openid
return $user->openid;
}
public function get_curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Linux; U; Android 4.4.1; zh-cn) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.5 Mobile Safari/533.1');
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
$ret = curl_exec($ch);
curl_close($ch);
return $ret;
}
}
+110
View File
@@ -0,0 +1,110 @@
<?php
namespace lib;
class QcloudFaceid {
private $SecretId;
private $SecretKey;
private $endpoint = "faceid.tencentcloudapi.com";
private $service = "faceid";
private $version = "2018-03-01";
private $region = "ap-guangzhou";
function __construct($SecretId, $SecretKey){
$this->SecretId = $SecretId;
$this->SecretKey = $SecretKey;
}
public function GetRealNameAuthToken($Name, $IDCard, $CallbackURL){
$action = 'GetRealNameAuthToken';
$param = [
'Name' => $Name,
'IDCard' => $IDCard,
'CallbackURL' => $CallbackURL
];
return $this->send_reuqest($action, $param);
}
public function GetRealNameAuthResult($AuthToken){
$action = 'GetRealNameAuthResult';
$param = [
'AuthToken' => $AuthToken
];
return $this->send_reuqest($action, $param);
}
private function send_reuqest($action, $param){
$payload = json_encode($param);
$time = time();
$authorization = $this->generateSign($payload, $time);
$header = [
'Authorization: '.$authorization,
'Content-Type: application/json; charset=utf-8',
'X-TC-Action: '.$action,
'X-TC-Timestamp: '.$time,
'X-TC-Version: '.$this->version,
'X-TC-Region: '.$this->region,
];
return $this->curl_post($payload, $header);
}
private function generateSign($payload, $time){
$algorithm = "TC3-HMAC-SHA256";
// step 1: build canonical request string
$httpRequestMethod = "POST";
$canonicalUri = "/";
$canonicalQueryString = "";
$canonicalHeaders = "content-type:application/json; charset=utf-8\n"."host:".$this->endpoint."\n";
$signedHeaders = "content-type;host";
$hashedRequestPayload = hash("SHA256", $payload);
$canonicalRequest = $httpRequestMethod."\n"
.$canonicalUri."\n"
.$canonicalQueryString."\n"
.$canonicalHeaders."\n"
.$signedHeaders."\n"
.$hashedRequestPayload;
// step 2: build string to sign
$date = gmdate("Y-m-d", $time);
$credentialScope = $date."/".$this->service."/tc3_request";
$hashedCanonicalRequest = hash("SHA256", $canonicalRequest);
$stringToSign = $algorithm."\n"
.$time."\n"
.$credentialScope."\n"
.$hashedCanonicalRequest;
// step 3: sign string
$secretDate = hash_hmac("SHA256", $date, "TC3".$this->SecretKey, true);
$secretService = hash_hmac("SHA256", $this->service, $secretDate, true);
$secretSigning = hash_hmac("SHA256", "tc3_request", $secretService, true);
$signature = hash_hmac("SHA256", $stringToSign, $secretSigning);
// step 4: build authorization
$authorization = $algorithm
." Credential=".$this->SecretId."/".$credentialScope
.", SignedHeaders=content-type;host, Signature=".$signature;
return $authorization;
}
private function curl_post($payload, $header){
$url = 'https://'.$this->endpoint.'/';
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
$json=curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($httpCode==200){
$arr=json_decode($json,true);
return $arr['Response'];
}else{
return false;
}
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace lib;
class Template {
static public function getList(){
$dir = TEMPLATE_ROOT;
$dirArray[] = NULL;
if (false != ($handle = opendir($dir))) {
$i = 0;
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != ".." && strpos($file, ".")===false) {
$dirArray[$i] = $file;
$i++;
}
}
closedir($handle);
}
return $dirArray;
}
static public function load($name = 'index'){
global $conf;
$template = $conf['template']?$conf['template']:'default';
if(!preg_match('/^[a-zA-Z0-9\_]+$/',$name))exit('error');
$filename = TEMPLATE_ROOT.$template.'/'.$name.'.php';
$filename_default = TEMPLATE_ROOT.'default/'.$name.'.php';
if(file_exists($filename)){
define("INDEX_ROOT",TEMPLATE_ROOT.$template.'/');
define("STATIC_ROOT",'/template/'.$template.'/assets/');
return $filename;
}elseif(file_exists($filename_default)){
define("INDEX_ROOT",TEMPLATE_ROOT.'default/');
define("STATIC_ROOT",'/template/default/assets/');
return $filename_default;
}else{
exit('Template file not found');
}
}
static public function loadDoc($name = 'index'){
if(!preg_match('/^[a-zA-Z0-9\_]+$/',$name))exit('error');
$filename = TEMPLATE_ROOT.'default/doc/'.$name.'.php';
if(file_exists($filename)){
return $filename;
}else{
exit('Document file not found');
}
}
static public function exists($template){
$filename = TEMPLATE_ROOT.$template.'/index.php';
if(file_exists($filename)){
return true;
}else{
return false;
}
}
}
+153
View File
@@ -0,0 +1,153 @@
<?php
namespace lib;
use Exception;
class Transfer
{
//通用转账
//type alipay:支付宝,wxpay:微信,qqpay:QQ钱包,bank:银行卡
public static function submit($type, $channel, $out_biz_no, $payee_account, $payee_real_name, $money, $desc = null){
global $conf;
$bizParam = [
'type' => $type,
'out_biz_no' => $out_biz_no,
'payee_account' => $payee_account,
'payee_real_name' => $payee_real_name,
'money' => $money,
'transfer_name' => $desc?$desc:$conf['transfer_name'],
'transfer_desc' => $desc?$desc:$conf['transfer_desc'],
];
return \lib\Plugin::call('transfer', $channel, $bizParam);
}
//转账状态刷新
public static function status($out_biz_no){
global $DB;
$order = $DB->find('transfer', '*', ['biz_no' => $out_biz_no]);
if(!$order) return ['code'=>-1, 'msg'=>'付款记录不存在'];
$channelinfo = null;
if($order['uid'] > 0){
$channelinfo = $DB->findColumn('user', 'channelinfo', ['uid'=>$order['uid']]);
}
$channel = \lib\Channel::get($order['channel'], $channelinfo);
if(!$channel) return ['code'=>-1, 'msg'=>'支付通道不存在'];
$result = self::query($order['type'], $channel, $out_biz_no, $order['pay_order_no']);
if($result['code'] == 0){
if($result['status'] == 2){
if($order['status'] == 0){
$resCount = $DB->update('transfer', ['status'=>2, 'result'=>$result['errmsg']], ['biz_no' => $out_biz_no]);
if($order['uid'] > 0 && $resCount > 0){
changeUserMoney($order['uid'], $order['costmoney'], true, '代付退回');
}
}
$result['msg'] = '转账失败:'.($result['errmsg']?$result['errmsg']:'原因未知');
}elseif($result['status'] == 1){
if($order['status'] == 0){
$paytime = $result['paydate'] ?? 'NOW()';
$DB->update('transfer', ['status'=>1, 'paytime'=>$paytime, 'result'=>''], ['biz_no' => $out_biz_no]);
}
$result['msg'] = '转账成功!';
}else{
$result['msg'] = '转账处理中,请稍后查询结果。';
}
}
return $result;
}
//转账查询
//status 0:处理中 1:成功 2:失败
public static function query($type, $channel, $out_biz_no, $pay_order_no){
$bizParam = [
'type' => $type,
'out_biz_no' => $out_biz_no,
'orderid' => $pay_order_no
];
return \lib\Plugin::call('transfer_query', $channel, $bizParam);
}
//撤销转账
public static function cancel($out_biz_no){
global $DB;
$order = $DB->find('transfer', '*', ['biz_no' => $out_biz_no]);
if(!$order) return ['code'=>-1, 'msg'=>'付款记录不存在'];
$channelinfo = null;
if($order['uid'] > 0){
$channelinfo = $DB->findColumn('user', 'channelinfo', ['uid'=>$order['uid']]);
}
$channel = \lib\Channel::get($order['channel'], $channelinfo);
if(!$channel) return ['code'=>-1, 'msg'=>'支付通道不存在'];
$bizParam = [
'type' => $order['type'],
'out_biz_no' => $order['biz_no'],
'orderid' => $order['pay_order_no'],
];
$result = \lib\Plugin::call('transfer_cancel', $channel, $bizParam);
if($result['code'] == 0){
$DB->update('transfer', ['status'=>2, 'result'=>'转账已撤销'], ['biz_no' => $out_biz_no]);
$result['msg'] = '转账已撤销';
}
return $result;
}
//账户余额查询
public static function balance($type, $channel, $user_id = null){
$bizParam = [
'type' => $type,
'user_id' => $user_id
];
return \lib\Plugin::call('balance_query', $channel, $bizParam);
}
//转账凭证查询
public static function proof($out_biz_no){
global $DB;
$order = $DB->find('transfer', '*', ['biz_no' => $out_biz_no]);
if(!$order) return ['code'=>-1, 'msg'=>'付款记录不存在'];
$channelinfo = null;
if($order['uid'] > 0){
$channelinfo = $DB->findColumn('user', 'channelinfo', ['uid'=>$order['uid']]);
}
$channel = \lib\Channel::get($order['channel'], $channelinfo);
if(!$channel) return ['code'=>-1, 'msg'=>'支付通道不存在'];
$bizParam = [
'type' => $order['type'],
'out_biz_no' => $out_biz_no,
'orderid' => $order['pay_order_no']
];
return \lib\Plugin::call('transfer_proof', $channel, $bizParam);
}
//转账回调处理
public static function processNotify($out_biz_no, $status, $errmsg = null){
global $DB;
$order = $DB->find('transfer', '*', ['biz_no' => $out_biz_no]);
if(!$order) {
$order = $DB->find('settle', '*', ['transfer_no' => $out_biz_no]);
if(!$order) return;
if($status == 2 && $order['transfer_status'] == 1){
$DB->update('settle', ['transfer_status'=>2, 'transfer_result'=>$errmsg, 'status'=>3, 'result'=>$errmsg], ['id' => $order['id']]);
}elseif($status == 1 && $order['transfer_status'] == 2){
$DB->update('settle', ['transfer_status'=>1, 'status'=>1, 'result'=>''], ['biz_no' => $out_biz_no]);
}
return;
}
if($status == 2 && $order['status'] == 0){ //转账失败
$data = ['status'=>2];
if($errmsg) $data['result'] = $errmsg;
$resCount = $DB->update('transfer', $data, ['biz_no' => $out_biz_no]);
if($order['uid'] > 0 && $resCount > 0){
changeUserMoney($order['uid'], $order['costmoney'], true, '代付退回');
}
}elseif($status == 1 && $order['status'] == 0){ //转账成功
$DB->update('transfer', ['status'=>1, 'paytime'=>'NOW()', 'result'=>''], ['biz_no' => $out_biz_no]);
}
}
}
+133
View File
@@ -0,0 +1,133 @@
<?php
namespace lib;
use Exception;
class VerifyCode{
const SMS_PHONE_DAYLY_TIME = 3; //短信验证码每个手机号每天最多发送次数
const SMS_IP_DAYLY_TIME = 6; //短信验证码每个IP每天最多发送次数
const EMAIL_ADDRESS_DAYLY_TIME = 7; //邮箱验证码每个邮箱每天最多发送次数
const EMAIL_IP_DAYLY_TIME = 11; //邮箱验证码每个IP每天最多发送次数
private static $regcodeid;
/**
* 发送验证码
* @param string $scene 验证码场景
* @param int $type 验证码类型:0邮件,1手机
* @param string $sendto 接收人
* @param int $uid 用户ID
* @return mixed
*/
public static function send_code($scene, $type, $sendto, $uid = 0){
global $DB, $conf, $clientip;
if($type == 1){
$phone = $sendto;
$row=$DB->getRow("select * from pre_regcode where `to`=:phone order by id desc limit 1", [':phone'=>$phone]);
if($row['time']>time()-60){
return '两次发送短信之间需要相隔60秒!';
}
$count=$DB->getColumn("select count(*) from pre_regcode where `to`=:phone and time>'".(time()-3600*24)."'", [':phone'=>$phone]);
if($count>=self::SMS_PHONE_DAYLY_TIME){
return '该手机号码发送次数过多,请更换号码!';
}
$count=$DB->getColumn("select count(*) from pre_regcode where ip=:ip and time>'".(time()-3600*24)."'", [':ip'=>$clientip]);
if($count>=self::SMS_IP_DAYLY_TIME){
return '你今天发送次数过多,请明天再试!';
}
$code = rand(111111,999999);
$result = send_sms($phone, $code, $scene);
if($result===true){
if($DB->insert('regcode', ['uid'=>$uid, 'scene'=>$scene, 'type'=>$type, 'code'=>$code, 'to'=>$phone, 'time'=>time(), 'ip'=>$clientip, 'status'=>0])){
return true;
}else{
return '写入数据库失败。'.$DB->error();
}
}else{
return '短信发送失败 '.$result;
}
}else{
$email = $sendto;
$row=$DB->getRow("select * from pre_regcode where `to`=:email order by id desc limit 1", [':email'=>$email]);
if($row['time']>time()-60){
return '两次发送邮件之间需要相隔60秒!';
}
$count=$DB->getColumn("select count(*) from pre_regcode where `to`=:email and time>'".(time()-3600*24)."'", [':email'=>$email]);
if($count>=self::EMAIL_ADDRESS_DAYLY_TIME){
return '该邮箱发送次数过多,请更换邮箱!';
}
$count=$DB->getColumn("select count(*) from pre_regcode where ip=:ip and time>'".(time()-3600*24)."'", [':ip'=>$clientip]);
if($count>=self::EMAIL_IP_DAYLY_TIME){
return '你今天发送次数过多,请明天再试!';
}
$code = rand(1111111,9999999);
$result = self::send_mail_code($email, $code, $scene);
if($result===true){
if($DB->insert('regcode', ['uid'=>$uid, 'scene'=>$scene, 'type'=>$type, 'code'=>$code, 'to'=>$email, 'time'=>time(), 'ip'=>$clientip, 'status'=>0])){
return true;
}else{
return '写入数据库失败。'.$DB->error();
}
}else{
return '邮件发送失败 '.$result;
}
}
}
private static function send_mail_code($email, $code, $scene){
global $conf;
$title = $conf['sitename'].' - 验证码获取';
if($scene == 'reg'){
$body = '您的验证码是:'.$code.',您正在注册成为'.$conf['sitename'].'的用户,如非本人操作请忽略。';
}elseif($scene == 'login'){
$body = '您的验证码是:'.$code.',用于'.$conf['sitename'].'登录验证,请勿泄露验证码,如非本人操作请忽略。';
}elseif($scene == 'find'){
$body = '您的验证码是:'.$code.',用于'.$conf['sitename'].'重置密码,请勿泄露验证码,如非本人操作请忽略。';
}elseif($scene == 'edit'){
global $situation;
if($situation=='settle')$body = '您正在修改结算账号信息,验证码是:'.$code;
elseif($situation=='mibao')$body = '您正在修改密保邮箱,验证码是:'.$code;
elseif($situation=='bind')$body = '您正在绑定新邮箱,验证码是:'.$code;
else $body = '您的验证码是:'.$code;
}
return send_mail($email, $title, $body);
}
/**
* 验证验证码
* @param string $scene 验证码场景
* @param int $type 验证码类型:0邮件,1手机
* @param string $sendto 接收人
* @param string $code 验证码
* @param int $uid 用户ID
* @return mixed
*/
public static function verify_code($scene, $type, $sendto, $code, $uid = 0){
global $DB;
$where = ['scene'=>$scene, 'type'=>$type, 'to'=>$sendto];
if($uid > 0) $where['uid'] = $uid;
$row = $DB->find('regcode', '*', $where, 'id DESC', 1);
if (!$row) {
return '请重新获取验证码!';
}elseif($row['time']<time()-3600 || $row['status']>0 || $row['errcount']>=5){
return '验证码已失效,请重新获取';
}elseif($row['code']!=$code){
$DB->exec("update `pre_regcode` set `errcount`=`errcount`+1 where `id`='{$row['id']}'");
return '验证码不正确!';
}
self::$regcodeid = $row['id'];
return true;
}
//作废验证码
public static function void_code(){
global $DB;
if(self::$regcodeid){
$DB->exec("update `pre_regcode` set `status`='1' where `id`=:id", [':id'=>self::$regcodeid]);
self::$regcodeid = null;
}
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
namespace lib\api;
use Exception;
class Merchant
{
public static function info(){
global $conf, $DB, $userrow, $queryArr;
$pid=intval($queryArr['pid']);
$orders=$DB->getColumn("SELECT count(*) from pre_order WHERE uid={$pid}");
$lastday=date("Y-m-d",strtotime("-1 day"));
$today=date("Y-m-d");
$order_today=$DB->getColumn("SELECT count(*) from pre_order where uid={$pid} and status=1 and date='$today'");
$order_lastday=$DB->getColumn("SELECT count(*) from pre_order where uid={$pid} and status=1 and date='$lastday'");
$order_today_all = round($DB->getColumn("SELECT sum(money) FROM pre_order WHERE uid={$pid} AND status=1 AND date='$today'"),2);
$order_lastday_all = round($DB->getColumn("SELECT sum(money) FROM pre_order WHERE uid={$pid} AND status=1 AND date='$lastday'"),2);
$result = ['code'=>0, 'pid'=>$pid, 'status'=>$userrow['status'], 'pay_status'=>$userrow['pay'], 'settle_status'=>$userrow['settle'], 'money'=>$userrow['money'], 'settle_type'=>$userrow['settle_id'], 'settle_account'=>$userrow['account'], 'settle_name'=>$userrow['username'], 'order_num'=>$orders, 'order_num_today'=>$order_today, 'order_num_lastday'=>$order_lastday, 'order_money_today'=>strval($order_today_all), 'order_money_lastday'=>strval($order_lastday_all)];
$result = array_filter($result, function($a){return !isEmpty($a);});
return $result;
}
public static function orders(){
global $conf, $DB, $userrow, $queryArr;
$pid=intval($queryArr['pid']);
$limit=isset($queryArr['limit'])?intval($queryArr['limit']):10;
$offset=isset($queryArr['offset'])?intval($queryArr['offset']):0;
$status=isset($queryArr['status'])?intval($queryArr['status']):null;
if($limit>50)$limit=50;
$sql = " uid='{$pid}'";
if(isset($queryArr['status'])){
$status = intval($_GET['status']);
$sql .= " AND A.status='{$status}'";
}
$data = [];
$rs=$DB->query("SELECT A.*,B.name typename FROM pre_order A LEFT JOIN pre_type B ON A.type=B.id WHERE{$sql} ORDER BY trade_no DESC LIMIT {$offset},{$limit}");
while($order=$rs->fetch(\PDO::FETCH_ASSOC)){
$data[]=['trade_no'=>$order['trade_no'],'out_trade_no'=>$order['out_trade_no'],'api_trade_no'=>$order['api_trade_no'],'type'=>$order['typename'],'pid'=>$order['uid'],'addtime'=>$order['addtime'],'endtime'=>$order['endtime'],'name'=>$order['name'],'money'=>$order['money'],'param'=>$order['param'],'buyer'=>$order['buyer'],'clientip'=>$order['ip'],'status'=>$order['status'],'refundmoney'=>$order['refundmoney']];
}
$result['code'] = 0;
$result['data'] = $data;
return $result;
}
}
+516
View File
@@ -0,0 +1,516 @@
<?php
namespace lib\api;
use Exception;
class Pay
{
public static function submit()
{
global $conf, $DB, $clientip, $order, $userrow;
@header('Content-Type: text/html; charset=UTF-8');
if(isset($_GET['pid'])){
$queryArr=$_GET;
}elseif(isset($_POST['pid'])){
$queryArr=$_POST;
}else{
exit('你还未配置支付接口商户!');
}
$pid=intval($queryArr['pid']);
if(empty($pid))sysmsg('商户ID不能为空');
$userrow=$DB->getRow("SELECT `uid`,`gid`,`key`,`money`,`mode`,`pay`,`cert`,`status`,`channelinfo`,`qq`,`ordername`,`keytype`,`publickey`,`deposit` FROM `pre_user` WHERE `uid`='{$pid}' LIMIT 1");
if(!$userrow)sysmsg('商户不存在!');
if(isset($queryArr['__defend'])){
$defend_result = $queryArr['__defend'];
unset($queryArr['__defend']);
}
try{
\lib\ApiHelper::api_verify($userrow, $queryArr);
}catch(Exception $e){
sysmsg($e->getMessage());
}
if($userrow['status']==0 || $userrow['pay']==0)sysmsg('商户已被封禁,无法支付!');
if($userrow['pay']==2 && $conf['user_review']==1)sysmsg('商户未通过审核,无法支付!');
$type=daddslashes($queryArr['type']);
$out_trade_no=daddslashes($queryArr['out_trade_no']);
$notify_url=htmlspecialchars(daddslashes($queryArr['notify_url']));
$return_url=htmlspecialchars(daddslashes($queryArr['return_url']));
$name=htmlspecialchars(daddslashes($queryArr['name']));
$money=daddslashes($queryArr['money']);
$sitename=urlencode(base64_encode(htmlspecialchars($queryArr['sitename'])));
$param=isset($queryArr['param'])?htmlspecialchars(daddslashes($queryArr['param'])):null;
if(empty($out_trade_no))sysmsg('订单号(out_trade_no)不能为空');
if(empty($notify_url))sysmsg('通知地址(notify_url)不能为空');
if(empty($return_url))sysmsg('回调地址(return_url)不能为空');
if(empty($name))sysmsg('商品名称(name)不能为空');
if(empty($money))sysmsg('金额(money)不能为空');
if($money<=0 || !is_numeric($money) || !preg_match('/^[0-9.]+$/', $money))sysmsg('金额不合法');
if($conf['pay_maxmoney']>0 && $money>$conf['pay_maxmoney'])sysmsg('最大支付金额是'.$conf['pay_maxmoney'].'元');
if($conf['pay_minmoney']>0 && $money<$conf['pay_minmoney'])sysmsg('最小支付金额是'.$conf['pay_minmoney'].'元');
if(!preg_match('/^[a-zA-Z0-9.\_\-|]+$/',$out_trade_no))sysmsg('订单号(out_trade_no)格式不正确');
$domain=getdomain($notify_url);
$groupconfig = getGroupConfig($userrow['gid']);
$conf = array_merge($conf, $groupconfig);
if($conf['cert_force']==1 && $userrow['cert']==0){
sysmsg('当前商户未完成实名认证,无法收款');
}
if($conf['forceqq']==1 && empty($userrow['qq'])){
sysmsg('当前商户未填写联系QQ,无法收款');
}
if($conf['pay_domain_forbid']==1){
if(!$DB->getRow("SELECT * FROM pre_domain WHERE uid=:uid AND (domain=:domain OR domain=:domain2) AND status=1 LIMIT 1", [':uid'=>$pid, ':domain'=>get_host($notify_url), ':domain2'=>'*.'.get_main_host($notify_url)])){
sysmsg('该域名不可发起支付,原因:域名没过白,请前往支付平台授权支付域名');
}
}
if($conf['user_deposit']==1 && $conf['user_deposit_min'] > 0 && $conf['user_deposit_min'] > $userrow['deposit']){
sysmsg('商户保证金不足,请前往支付平台充值保证金后再发起支付');
}
if(!empty($conf['blockname'])){
$block_name = explode('|',$conf['blockname']);
foreach($block_name as $rows){
if(!empty($rows) && strpos($name,$rows)!==false){
$DB->exec("INSERT INTO `pre_risk` (`uid`, `url`, `content`, `date`) VALUES (:uid, :domain, :rows, NOW())", [':uid'=>$pid,':domain'=>$domain,':rows'=>$rows]);
sysmsg($conf['blockalert']?$conf['blockalert']:'该商品禁止出售');
}
}
}
$blackip = $DB->find('blacklist', '*', ['type'=>1, 'content'=>$clientip], null, 1);
if($blackip)sysmsg('系统异常无法完成付款');
if($conf['pay_iplimit'] > 0){
$ipcount = $DB->getColumn("select count(*) from pre_order where `ip`='$clientip' and `date`='".date('Y-m-d')."' and status>0");
if($ipcount >= $conf['pay_iplimit']){
sysmsg('你今天已无法再发起支付,请明天再试');
}
}
if(checkPayVerifyOpen($pid)){
$defend_key = getDefendKey($pid, $out_trade_no);
if(empty($defend_result) || $defend_key!==substr($defend_result,10,32)){
showPayVerifyPage($defend_key, $queryArr);
}
}
if(strlen($name)>127)$name=mb_strcut($name, 0, 127, 'utf-8');
$firstGetChannel = true;
$oldorder = $DB->getRow("SELECT * FROM `pre_order` WHERE `uid`=:uid AND `out_trade_no`=:out_trade_no", [':uid'=>$pid, ':out_trade_no'=>$out_trade_no]);
if($oldorder && time() - strtotime($oldorder['addtime']) < 864000){
if($oldorder['status']>0){
sysmsg('该订单('.$out_trade_no.')已完成支付,请勿重复发起支付');
}
if(round($oldorder['money'],2) != round($money,2) || $oldorder['name'] != $name || $oldorder['notify_url'] != $notify_url || $oldorder['return_url'] != $return_url || $oldorder['param'] != $param){
sysmsg('该订单('.$out_trade_no.')支付参数有变化,请更换订单号重新发起支付');
}
$trade_no=$oldorder['trade_no'];
$typeid = $DB->getColumn("SELECT id FROM pre_type WHERE name=:name LIMIT 1", [':name'=>$type]);
if($oldorder['type'] > 0 && $oldorder['channel'] > 0 && $oldorder['realmoney'] > 0 && $oldorder['getmoney'] > 0 && $typeid == $oldorder['type']){ //订单已经获取过支付通道信息
$firstGetChannel = false;
}
}else{
$version = defined('API_INIT') ? 1 : 0;
$trade_no=date("YmdHis").rand(11111,99999);
if(!$DB->exec("INSERT INTO `pre_order` (`trade_no`,`out_trade_no`,`uid`,`addtime`,`name`,`money`,`notify_url`,`return_url`,`param`,`domain`,`ip`,`status`,`version`) VALUES (:trade_no, :out_trade_no, :uid, NOW(), :name, :money, :notify_url, :return_url, :param, :domain, :clientip, 0, :version)", [':trade_no'=>$trade_no, ':out_trade_no'=>$out_trade_no, ':uid'=>$pid, ':name'=>$name, ':money'=>$money, ':notify_url'=>$notify_url, ':return_url'=>$return_url, ':domain'=>$domain, ':clientip'=>$clientip, ':param'=>$param, ':version'=>$version]))sysmsg('创建订单失败,请返回重试!');
}
if(empty($type)){
echo "<script>window.location.replace('/cashier.php?trade_no={$trade_no}&sitename={$sitename}');</script>";
exit;
}
// 获取订单支付方式ID、支付插件、支付通道、支付费率
if($firstGetChannel){
$submitData = \lib\Channel::submit($type, $userrow['uid'], $userrow['gid'], $money);
if(!$submitData){
echo "<script>window.location.replace('/cashier.php?trade_no={$trade_no}&sitename={$sitename}&other=1');</script>";
exit;
}
if($userrow['mode']==1){ //订单加费模式
$realmoney = round($money*(100+100-$submitData['rate'])/100,2);
$getmoney = $money;
if($conf['payfee_lessthan'] > 0 && $conf['payfee_mincost'] > 0){
$feemoney = round($money*(100-$submitData['rate'])/100,2);
if($feemoney < round($conf['payfee_lessthan'], 2)){
$realmoney = round($money + $conf['payfee_mincost'], 2);
}
}
}else{
$realmoney = $money;
$getmoney = round($money*$submitData['rate']/100,2);
if($conf['payfee_lessthan'] > 0 && $conf['payfee_mincost'] > 0){
$feemoney = round($money*(100-$submitData['rate'])/100,2);
if($feemoney < round($conf['payfee_lessthan'], 2)){
$getmoney = round($money - $conf['payfee_mincost'], 2);
if($getmoney < 0) $getmoney = 0;
}
}
}
}else{
$submitData = \lib\Channel::info($oldorder['channel']);
$submitData['typename'] = $type;
$submitData['subchannel'] = $oldorder['subchannel'];
$realmoney = $oldorder['realmoney'];
$getmoney = $oldorder['getmoney'];
}
// 判断通道单笔支付限额
if(!empty($submitData['paymin']) && $submitData['paymin']>0 && $money<$submitData['paymin']){
sysmsg('<center>当前支付方式单笔最小限额为'.$submitData['paymin'].'元,请选择其他支付方式!</center>', '跳转提示');
}
if(!empty($submitData['paymax']) && $submitData['paymax']>0 && $money>$submitData['paymax']){
sysmsg('<center>当前支付方式单笔最大限额为'.$submitData['paymax'].'元,请选择其他支付方式!</center>', '跳转提示');
}
// 商户直清模式判断商户余额
if($submitData['mode']==1 && $realmoney-$getmoney>$userrow['money']){
sysmsg('当前商户余额不足,无法完成支付,请商户登录用户中心充值余额');
}
if($firstGetChannel){
// 随机增减金额
if(!empty($conf['pay_payaddstart'])&&$conf['pay_payaddstart']!=0&&!empty($conf['pay_payaddmin'])&&$conf['pay_payaddmin']!=0&&!empty($conf['pay_payaddmax'])&&$conf['pay_payaddmax']!=0&&$realmoney>=$conf['pay_payaddstart'])$realmoney = round($realmoney + randomFloat(round($conf['pay_payaddmin'],2),round($conf['pay_payaddmax'],2)), 2);
$DB->update('order', ['type'=>$submitData['typeid'], 'channel'=>$submitData['channel'], 'subchannel'=>$submitData['subchannel'], 'realmoney'=>$realmoney, 'getmoney'=>$getmoney], ['trade_no'=>$trade_no]);
}
$order['trade_no'] = $trade_no;
$order['out_trade_no'] = $out_trade_no;
$order['uid'] = $pid;
$order['addtime'] = date('Y-m-d H:i:s');
$order['name'] = $name;
$order['realmoney'] = $realmoney;
$order['type'] = $submitData['typeid'];
$order['channel'] = $submitData['channel'];
$order['subchannel'] = $submitData['subchannel'];
$order['typename'] = $submitData['typename'];
$order['plugin'] = $submitData['plugin'];
$order['profits'] = \lib\Payment::updateOrderProfits($order, $submitData['plugin']);
try{
$result = \lib\Plugin::loadForSubmit($submitData['plugin'], $trade_no);
$result['submit'] = true;
\lib\Payment::echoDefault($result);
}catch(Exception $e){
sysmsg($e->getMessage());
}
}
public static function create(){
global $conf, $DB, $clientip, $order, $userrow, $method, $device, $mdevice, $siteurl;
if(isset($_POST['pid'])){
$queryArr=$_POST;
}else{
echojsonmsg('未传入任何参数', -4);
}
$pid=intval($queryArr['pid']);
if(empty($pid))echojsonmsg('商户ID不能为空');
$userrow=$DB->getRow("SELECT `uid`,`gid`,`key`,`money`,`mode`,`pay`,`cert`,`status`,`channelinfo`,`qq`,`ordername`,`keytype`,`publickey`,`deposit` FROM `pre_user` WHERE `uid`='{$pid}' LIMIT 1");
if(!$userrow)echojsonmsg('商户不存在!');
try{
\lib\ApiHelper::api_verify($userrow, $queryArr);
}catch(Exception $e){
echojsonmsg($e->getMessage(), -3);
}
if($userrow['status']==0 || $userrow['pay']==0)echojsonmsg('商户已被封禁,无法支付!');
if($userrow['pay']==2 && $conf['user_review']==1)echojsonmsg('商户未通过审核,无法支付!');
$type=daddslashes($queryArr['type']);
$out_trade_no=daddslashes($queryArr['out_trade_no']);
$notify_url=htmlspecialchars(daddslashes($queryArr['notify_url']));
$return_url=htmlspecialchars(daddslashes($queryArr['return_url']));
$name=htmlspecialchars(daddslashes($queryArr['name']));
$money=daddslashes($queryArr['money']);
$clientip=daddslashes($queryArr['clientip']);
$device=$queryArr['device'];
if(empty($device))$device = 'pc';
$sub_openid=$queryArr['sub_openid'];
$sub_appid=$queryArr['sub_appid'];
$auth_code=$queryArr['auth_code'];
$sitename=urlencode(base64_encode(htmlspecialchars($queryArr['sitename'])));
$param=isset($queryArr['param'])?htmlspecialchars(daddslashes($queryArr['param'])):null;
$method=$queryArr['method']; //web/jump/jsapi/scan
if($device == 'jump')$method = 'jump';
$mdevice='';
if ($device=='qq'||$device=='wechat'||$device=='alipay'||$device=='app') {
$mdevice=$device;
$device='mobile';
}
if(empty($out_trade_no))echojsonmsg('订单号(out_trade_no)不能为空');
if(empty($notify_url))echojsonmsg('通知地址(notify_url)不能为空');
if(empty($name))echojsonmsg('商品名称(name)不能为空');
if(empty($money))echojsonmsg('金额(money)不能为空');
if(empty($type) && $method != 'scan')echojsonmsg('支付方式(type)不能为空');
if(empty($clientip))echojsonmsg('用户IP地址(clientip)不能为空');
if($money<=0 || !is_numeric($money) || !preg_match('/^[0-9.]+$/', $money))echojsonmsg('金额不合法');
if($conf['pay_maxmoney']>0 && $money>$conf['pay_maxmoney'])echojsonmsg('最大支付金额是'.$conf['pay_maxmoney'].'元');
if($conf['pay_minmoney']>0 && $money<$conf['pay_minmoney'])echojsonmsg('最小支付金额是'.$conf['pay_minmoney'].'元');
if(!preg_match('/^[a-zA-Z0-9.\_\-|]+$/',$out_trade_no))echojsonmsg('订单号(out_trade_no)格式不正确');
if($method == 'jsapi' && empty($sub_openid))echojsonmsg('jsapi支付时参数(sub_openid)不能为空');
if($method == 'jsapi' && $type=='wxpay' && empty($sub_appid))echojsonmsg('jsapi支付时参数(sub_appid)不能为空');
if($method == 'scan' && empty($auth_code))echojsonmsg('付款码支付时授权码(auth_code)不能为空');
if($method == 'scan' && empty($type)){
$type = getScanPayType($auth_code);
if($type == 'unknown') echojsonmsg('未知的付款码类型');
}
$groupconfig = getGroupConfig($userrow['gid']);
$conf = array_merge($conf, $groupconfig);
$domain=getdomain($notify_url);
if($conf['cert_force']==1 && $userrow['cert']==0){
echojsonmsg('当前商户未完成实名认证,无法收款');
}
if($conf['forceqq']==1 && empty($userrow['qq'])){
echojsonmsg('当前商户未填写联系QQ,无法收款');
}
if($conf['pay_domain_forbid']==1){
if(!$DB->getRow("SELECT * FROM pre_domain WHERE uid=:uid AND (domain=:domain OR domain=:domain2) AND status=1 LIMIT 1", [':uid'=>$pid, ':domain'=>get_host($notify_url), ':domain2'=>'*.'.get_main_host($notify_url)])){
echojsonmsg('该域名不可发起支付,原因:域名没过白,请前往支付平台授权支付域名');
}
}
if($conf['user_deposit']==1 && $conf['user_deposit_min'] > 0 && $conf['user_deposit_min'] > $userrow['deposit']){
echojsonmsg('商户保证金不足,请前往支付平台充值保证金后再发起支付');
}
if(!empty($conf['blockname'])){
$block_name = explode('|',$conf['blockname']);
foreach($block_name as $rows){
if(!empty($rows) && strpos($name,$rows)!==false){
$DB->exec("INSERT INTO `pre_risk` (`uid`, `url`, `content`, `date`) VALUES (:uid, :domain, :rows, NOW())", [':uid'=>$pid,':domain'=>$domain,':rows'=>$rows]);
echojsonmsg($conf['blockalert']?$conf['blockalert']:'该商品禁止出售');
}
}
}
$blackip = $DB->find('blacklist', '*', ['type'=>1, 'content'=>$clientip], null, 1);
if($blackip)echojsonmsg('系统异常无法完成付款');
if($conf['pay_iplimit'] > 0){
$ipcount = $DB->getColumn("select count(*) from pre_order where `ip`='$clientip' and `date`='".date('Y-m-d')."' and status>0");
if($ipcount >= $conf['pay_iplimit']){
echojsonmsg('你今天已无法再发起支付,请明天再试');
}
}
if(checkPayVerifyOpen($pid)){
echojsonmsg('本次支付需要安全验证,请使用跳转支付接口发起支付');
}
if(strlen($name)>127)$name=mb_strcut($name, 0, 127, 'utf-8');
$firstGetChannel = true;
$oldorder = $DB->getRow("SELECT * FROM `pre_order` WHERE `uid`=:uid AND `out_trade_no`=:out_trade_no", [':uid'=>$pid, ':out_trade_no'=>$out_trade_no]);
if($oldorder && time() - strtotime($oldorder['addtime']) < 864000){
if($oldorder['status']>0){
echojsonmsg('该订单('.$out_trade_no.')已完成支付,请勿重复发起支付');
}
if(round($oldorder['money'],2) != round($money,2) || $oldorder['name'] != $name || $oldorder['notify_url'] != $notify_url || $oldorder['return_url'] != $return_url || $oldorder['param'] != $param){
echojsonmsg('该订单('.$out_trade_no.')支付参数有变化,请更换订单号重新发起支付');
}
$trade_no=$oldorder['trade_no'];
$typeid = $DB->getColumn("SELECT id FROM pre_type WHERE name=:name LIMIT 1", [':name'=>$type]);
if($oldorder['type'] > 0 && $oldorder['channel'] > 0 && $oldorder['realmoney'] > 0 && $oldorder['getmoney'] > 0 && $typeid == $oldorder['type']){ //订单已经获取过支付通道信息
$firstGetChannel = false;
}
}else{
$version = defined('API_INIT') ? 1 : 0;
$trade_no=date("YmdHis").rand(11111,99999);
if(!$DB->exec("INSERT INTO `pre_order` (`trade_no`,`out_trade_no`,`uid`,`addtime`,`name`,`money`,`notify_url`,`return_url`,`param`,`domain`,`ip`,`status`,`version`) VALUES (:trade_no, :out_trade_no, :uid, NOW(), :name, :money, :notify_url, :return_url, :param, :domain, :clientip, 0, :version)", [':trade_no'=>$trade_no, ':out_trade_no'=>$out_trade_no, ':uid'=>$pid, ':name'=>$name, ':money'=>$money, ':notify_url'=>$notify_url, ':return_url'=>$return_url, ':domain'=>$domain, ':clientip'=>$clientip, ':param'=>$param, ':version'=>$version]))echojsonmsg('创建订单失败,请返回重试!');
}
if(empty($type)){
define("TRADE_NO", $trade_no);
\lib\Payment::echoJson(['type'=>'jump','url'=>$siteurl.'cashier.php?trade_no='.$trade_no.'&sitename='.$sitename]);
}
// 获取订单支付方式ID、支付插件、支付通道、支付费率
if($firstGetChannel){
$submitData = \lib\Channel::submit($type, $userrow['uid'], $userrow['gid'], $money);
if(!$submitData){
define("TRADE_NO", $trade_no);
\lib\Payment::echoJson(['type'=>'jump','url'=>$siteurl.'cashier.php?trade_no='.$trade_no.'&sitename='.$sitename.'&other=1']);
}
if($userrow['mode']==1){ //订单加费模式
$realmoney = round($money*(100+100-$submitData['rate'])/100,2);
$getmoney = $money;
if($conf['payfee_lessthan'] > 0 && $conf['payfee_mincost'] > 0){
$feemoney = round($money*(100-$submitData['rate'])/100,2);
if($feemoney < round($conf['payfee_lessthan'], 2)){
$realmoney = round($money + $conf['payfee_mincost'], 2);
}
}
}else{
$realmoney = $money;
$getmoney = round($money*$submitData['rate']/100,2);
if($conf['payfee_lessthan'] > 0 && $conf['payfee_mincost'] > 0){
$feemoney = round($money*(100-$submitData['rate'])/100,2);
if($feemoney < round($conf['payfee_lessthan'], 2)){
$getmoney = round($money - $conf['payfee_mincost'], 2);
if($getmoney < 0) $getmoney = 0;
}
}
}
}else{
$submitData = \lib\Channel::info($oldorder['channel']);
$submitData['typename'] = $type;
$submitData['subchannel'] = $oldorder['subchannel'];
$realmoney = $oldorder['realmoney'];
$getmoney = $oldorder['getmoney'];
}
// 判断通道单笔支付限额
if(!empty($submitData['paymin']) && $submitData['paymin']>0 && $money<$submitData['paymin']){
echojsonmsg('当前支付方式单笔最小限额为'.$submitData['paymin'].'元,请选择其他支付方式!');
}
if(!empty($submitData['paymax']) && $submitData['paymax']>0 && $money>$submitData['paymax']){
echojsonmsg('当前支付方式单笔最大限额为'.$submitData['paymax'].'元,请选择其他支付方式!');
}
// 商户直清模式判断商户余额
if($submitData['mode']==1 && $realmoney-$getmoney>$userrow['money']){
echojsonmsg('当前商户余额不足,无法完成支付,请商户登录用户中心充值余额');
}
if($firstGetChannel){
// 随机增减金额
if(!empty($conf['pay_payaddstart'])&&$conf['pay_payaddstart']!=0&&!empty($conf['pay_payaddmin'])&&$conf['pay_payaddmin']!=0&&!empty($conf['pay_payaddmax'])&&$conf['pay_payaddmax']!=0&&$realmoney>=$conf['pay_payaddstart'])$realmoney = $realmoney + randomFloat(round($conf['pay_payaddmin'],2),round($conf['pay_payaddmax'],2));
$DB->update('order', ['type'=>$submitData['typeid'], 'channel'=>$submitData['channel'], 'subchannel'=>$submitData['subchannel'], 'realmoney'=>$realmoney, 'getmoney'=>$getmoney], ['trade_no'=>$trade_no]);
}
$order['trade_no'] = $trade_no;
$order['out_trade_no'] = $out_trade_no;
$order['uid'] = $pid;
$order['addtime'] = date('Y-m-d H:i:s');
$order['name'] = $name;
$order['realmoney'] = $realmoney;
$order['type'] = $submitData['typeid'];
$order['channel'] = $submitData['channel'];
$order['subchannel'] = $submitData['subchannel'];
$order['typename'] = $submitData['typename'];
$order['plugin'] = $submitData['plugin'];
$order['profits'] = \lib\Payment::updateOrderProfits($order, $submitData['plugin']);
$order['sub_openid'] = $sub_openid;
$order['sub_appid'] = $sub_appid;
$order['auth_code'] = $auth_code;
if($method == 'jump'){
define("TRADE_NO", $trade_no);
\lib\Payment::echoJson(['type'=>'jump','url'=>$siteurl.'pay/submit/'.$trade_no.'/']);
}
try{
$result = \lib\Plugin::loadForSubmit($submitData['plugin'], $trade_no, true);
\lib\Payment::echoJson($result);
}catch(Exception $e){
echojsonmsg($e->getMessage());
}
}
public static function query(){
global $conf, $DB, $queryArr;
$pid=intval($queryArr['pid']);
if(!empty($queryArr['trade_no'])){
$trade_no=daddslashes($queryArr['trade_no']);
$order=$DB->getRow("SELECT * FROM pre_order WHERE uid='{$pid}' and trade_no='{$trade_no}' limit 1");
}elseif(!empty($queryArr['out_trade_no'])){
$out_trade_no=daddslashes($queryArr['out_trade_no']);
$order=$DB->getRow("SELECT * FROM pre_order WHERE uid='{$pid}' and out_trade_no='{$out_trade_no}' limit 1");
}else{
throw new Exception('订单号不能为空');
}
if($order){
$type=$DB->getColumn("SELECT name FROM pre_type WHERE id='{$order['type']}' LIMIT 1");
$result = ['code'=>0, 'trade_no'=>$order['trade_no'],'out_trade_no'=>$order['out_trade_no'],'api_trade_no'=>$order['api_trade_no'],'bill_trade_no'=>$order['bill_trade_no'],'type'=>$type,'pid'=>$order['uid'],'addtime'=>$order['addtime'],'endtime'=>$order['endtime'],'name'=>$order['name'],'money'=>$order['money'],'param'=>$order['param'],'buyer'=>$order['buyer'],'clientip'=>$order['ip'],'status'=>$order['status'],'refundmoney'=>$order['refundmoney']];
$result = array_filter($result, function($a){return !isEmpty($a);});
return $result;
}else{
throw new Exception('订单号不存在');
}
}
public static function refund(){
global $conf, $DB, $userrow, $queryArr;
$pid=intval($queryArr['pid']);
if(!$conf['user_refund']) throw new Exception('管理员未开启商户后台自助退款');
$money = trim($queryArr['money']);
if(!is_numeric($money) || !preg_match('/^[0-9.]+$/', $money))throw new Exception('金额输入错误');
if(!empty($queryArr['trade_no'])){
$trade_no=daddslashes($queryArr['trade_no']);
}elseif(!empty($queryArr['out_trade_no'])){
$out_trade_no=daddslashes($queryArr['out_trade_no']);
$trade_no = $DB->findColumn('order', 'trade_no', ['out_trade_no'=>$out_trade_no, 'uid'=>$pid]);
if(!$trade_no) throw new Exception('当前订单不存在!');;
}else{
throw new Exception('订单号不能为空');
}
$refund_no = date("YmdHis").rand(11111,99999);
if(!empty($queryArr['out_refund_no']) && strlen($queryArr['out_refund_no']) > 5){ //判断商户是否重复提交退款
$out_refund_no = daddslashes($queryArr['out_refund_no']);
$refund_order = $DB->find('refundorder', '*', ['out_refund_no'=>$out_refund_no, 'uid'=>$pid]);
if($refund_order && $refund_order['status'] == 1){
$result = ['code'=>0, 'refund_no'=>$refund_order['refund_no'], 'out_refund_no'=>$refund_order['out_refund_no'], 'trade_no'=>$refund_order['trade_no'], 'uid'=>$refund_order['uid'], 'money'=>$refund_order['money'], 'reducemoney'=>$refund_order['reducemoney'], 'msg'=>'已存在相同退款单号!退款金额¥'.$refund_order['money']];
return $result;
}elseif($refund_order && $refund_order['status'] == 0){
$refund_no = $refund_order['refund_no'];
}
}
$result = \lib\Order::refund($refund_no, $trade_no, $money, 1, $pid, $out_refund_no);
if($result['code'] == 0){
$result['msg'] = '退款成功!退款金额¥'.$result['money'];
}
return $result;
}
public static function refundquery(){
global $conf, $DB, $queryArr;
$pid=intval($queryArr['pid']);
if(!$conf['user_refund']) throw new Exception('管理员未开启商户后台自助退款');
if(!empty($queryArr['refund_no'])){
$refund_no=daddslashes($queryArr['refund_no']);
$refund_order = $DB->find('refundorder', '*', ['refund_no'=>$refund_no, 'uid'=>$pid]);
}elseif(!empty($queryArr['out_refund_no'])){
$out_refund_no=daddslashes($queryArr['out_refund_no']);
$refund_order = $DB->find('refundorder', '*', ['out_refund_no'=>$out_refund_no, 'uid'=>$pid]);
}else{
throw new Exception('商户退款单号不能为空');
}
if(!$refund_order)throw new Exception('退款记录不存在');
$out_trade_no = $DB->findColumn('order', 'out_trade_no', ['trade_no'=>$refund_order['trade_no']]);
$result = ['code'=>0, 'refund_no'=>$refund_order['refund_no'], 'out_refund_no'=>$refund_order['out_refund_no'], 'trade_no'=>$refund_order['trade_no'], 'out_trade_no'=>$out_trade_no, 'uid'=>$refund_order['uid'], 'money'=>$refund_order['money'], 'reducemoney'=>$refund_order['reducemoney'], 'status'=>$refund_order['status'], 'addtime'=>$refund_order['addtime'], 'endtime'=>$refund_order['endtime']];
return $result;
}
}
+186
View File
@@ -0,0 +1,186 @@
<?php
namespace lib\api;
use Exception;
class Transfer
{
public static function submit(){
global $conf, $DB, $userrow, $queryArr, $siteurl;
$pid=intval($queryArr['pid']);
$groupconfig = getGroupConfig($userrow['gid']);
$conf = array_merge($conf, $groupconfig);
if(!$conf['user_transfer']) throw new Exception('管理员未开启代付功能');
if($userrow['transfer'] == 0) throw new Exception('商户未开启代付API接口');
if($conf['settle_type']==1){
$today=date("Y-m-d").' 00:00:00';
$order_today=$DB->getColumn("SELECT SUM(realmoney) from pre_order where uid={$pid} and tid<>2 and status=1 and endtime>='$today'");
if(!$order_today) $order_today = 0;
$enable_money=round($userrow['money']-$order_today,2);
if($enable_money<0)$enable_money=0;
}else{
$enable_money=$userrow['money'];
}
if(!$conf['transfer_rate'])$conf['transfer_rate'] = $conf['settle_rate'];
$type = $queryArr['type'];
$out_biz_no = trim($queryArr['out_biz_no']);
$account = htmlspecialchars(trim($queryArr['account']));
$name = htmlspecialchars(trim($queryArr['name']));
$money = trim($queryArr['money']);
$desc = htmlspecialchars(trim($queryArr['remark']));
if(empty($type))throw new Exception('代付方式(type)不能为空');
if(empty($out_biz_no)) $out_biz_no = date("YmdHis").rand(11111,99999);
if(empty($account))throw new Exception('收款人账号(account)不能为空');
if(empty($name))throw new Exception('收款人姓名(name)不能为空');
if(empty($money))throw new Exception('转账金额(money)不能为空');
if(strlen($out_biz_no)!=19 || !is_numeric($out_biz_no))throw new Exception('交易号输入不规范');
if($desc && mb_strlen($desc)>32)throw new Exception('转账备注最多32个字');
if(!is_numeric($money) || !preg_match('/^[0-9.]+$/', $money) || $money<=0)throw new Exception('转账金额输入不规范');
$need_money = round($money + $money*$conf['transfer_rate']/100,2);
if($need_money>$enable_money)throw new Exception('需支付金额大于可转账余额');
if($conf['transfer_minmoney']>0 && $money<$conf['transfer_minmoney'])throw new Exception('单笔最小代付金额限制为'.$conf['transfer_minmoney'].'元');
if($conf['transfer_maxmoney']>0 && $money>$conf['transfer_maxmoney'])throw new Exception('单笔最大代付金额限制为'.$conf['transfer_maxmoney'].'元');
if($userrow['settle']==0)throw new Exception('您的商户出现异常,无法使用代付功能');
if($conf['transfer_maxlimit']>0){
$a_count = $DB->getColumn('SELECT count(*) FROM pre_transfer WHERE uid=:uid AND type=:type AND account=:account AND paytime>=:paytime', [':uid'=>$pid, ':type'=>$type, ':account'=>$account, ':paytime'=>date('Y-m-d').' 00:00:00']);
if($a_count >= $conf['transfer_maxlimit']){
throw new Exception('您今天向该账号的转账次数已达到上限');
}
}
if($type=='alipay'){
$channelid = $conf['transfer_alipay'];
}elseif($type=='wxpay'){
$channelid = $conf['transfer_wxpay'];
}elseif($type=='qqpay'){
if (!is_numeric($account) || strlen($account)<6 || strlen($account)>10)throw new Exception('QQ号码格式错误');
$channelid = $conf['transfer_qqpay'];
}elseif($type=='bank'){
$channelid = $conf['transfer_bank'];
}else{
throw new Exception('type参数错误');
}
if(!$channelid) throw new Exception('未开启此转账方式');
$channel = \lib\Channel::get($channelid, $userrow['channelinfo']);
if(!$channel)throw new Exception('当前支付通道信息不存在',4);
if(class_exists('\\lib\\AlipaySATF\\AlipaySATF') && $conf['alipay_satf']==1 && ($type=='alipay' || $type=='bank' && $conf['transfer_alipay']==$conf['transfer_bank'])){
$bookid = $queryArr['bookid'];
if(!$bookid) $bookid = $DB->findColumn('satf_account_book', 'id', ['uid'=>$pid, 'status'=>1], 'money DESC');
$satf = new \lib\AlipaySATF\AlipaySATF();
$params = [
'out_biz_no' => $out_biz_no,
'account' => $account,
'name' => $name,
'money' => $money,
'remark' => $desc,
];
$result = $satf->transfer($bookid, $type=='bank' ? 2 : 1, $params, $pid);
return $result;
}
$result = \lib\Transfer::submit($type, $channel, $out_biz_no, $account, $name, $money, $desc);
$result['out_biz_no'] = $out_biz_no;
if($result['code']==0){
$paytime = $result['status'] == 1 ? 'NOW()' : null;
$data = ['biz_no'=>$out_biz_no, 'uid'=>$pid, 'type'=>$type, 'channel'=>$channelid, 'account'=>$account, 'username'=>$name, 'money'=>$money, 'costmoney'=>$need_money, 'addtime'=>'NOW()', 'paytime'=>$paytime, 'pay_order_no'=>$result['orderid'], 'status'=>$result['status'], 'desc'=>$desc];
if(isset($result['wxpackage'])) $data['ext'] = $result['wxpackage'];
$id = $DB->insert('transfer', $data);
if($id!==false){
changeUserMoney($pid, $need_money, false, '代付');
}
if($result['status'] == 1){
$result['msg']='转账成功!转账单据号:'.$result['orderid'].' 支付时间:'.$result['paydate'];
}elseif(isset($result['wxpackage'])){
$jumpurl = $siteurl.'paypage/wxtrans.php?type=transfer&id='.$id;
$result='提交成功!请在微信打开 '.$jumpurl.' 确认收款。转账单据号:'.$result['orderid'].' 支付时间:'.$result['paydate'];
$result['jumpurl'] = $jumpurl;
}else{
$result['msg']='提交成功!转账处理中。转账单据号:'.$result['orderid'].' 支付时间:'.$result['paydate'];
}
$result['cost_money'] = $need_money;
}
return $result;
}
public static function query(){
global $conf, $DB, $userrow, $queryArr;
$pid=intval($queryArr['pid']);
$groupconfig = getGroupConfig($userrow['gid']);
$conf = array_merge($conf, $groupconfig);
if(!$conf['user_transfer']) throw new Exception('管理员未开启代付功能');
if($userrow['transfer'] == 0) throw new Exception('商户未开启代付API接口');
$out_biz_no = trim($queryArr['out_biz_no']);
if(empty($out_biz_no)) throw new Exception('转账交易号(out_biz_no)不能为空');
$order = $DB->find('transfer', '*', ['biz_no'=>$out_biz_no, 'uid'=>$pid]);
if(!$order) throw new Exception('当前转账订单不存在');
if($order['status'] == 1){
$result = ['code'=>0, 'msg'=>'转账成功!', 'status'=>1, 'amount'=>$order['money'], 'cost_money'=>$order['costmoney'], 'paydate'=>$order['paytime'], 'remark'=>$order['desc']];
}elseif($order['status'] == 2){
$errmsg = ($order['result']?$order['result']:'原因未知');
$result = ['code'=>0, 'msg'=>'转账失败:'.($order['result']?$order['result']:'原因未知'), 'status'=>2, 'amount'=>$order['money'], 'cost_money'=>$order['money'], 'paydate'=>$order['paytime'], 'remark'=>$order['desc'], 'errmsg'=>$errmsg];
}else{
$result = \lib\Transfer::status($out_biz_no);
$result['remark'] = $order['desc'];
$result['cost_money'] = $order['costmoney'];
}
return $result;
}
public static function proof(){
global $conf, $DB, $userrow, $queryArr;
$pid=intval($queryArr['pid']);
$groupconfig = getGroupConfig($userrow['gid']);
$conf = array_merge($conf, $groupconfig);
if(!$conf['user_transfer']) throw new Exception('管理员未开启代付功能');
if($userrow['transfer'] == 0) throw new Exception('商户未开启代付API接口');
$out_biz_no = trim($queryArr['out_biz_no']);
if(empty($out_biz_no)) throw new Exception('转账交易号(out_biz_no)不能为空');
$order = $DB->find('transfer', '*', ['biz_no'=>$out_biz_no, 'uid'=>$pid]);
if(!$order) throw new Exception('当前转账订单不存在');
$result = \lib\Transfer::proof($out_biz_no);
return $result;
}
public static function balance(){
global $conf, $DB, $userrow, $queryArr;
$pid=intval($queryArr['pid']);
$groupconfig = getGroupConfig($userrow['gid']);
$conf = array_merge($conf, $groupconfig);
if(!$conf['user_transfer']) throw new Exception('管理员未开启代付功能');
if($userrow['transfer'] == 0) throw new Exception('商户未开启代付API接口');
if($conf['settle_type']==1){
$today=date("Y-m-d").' 00:00:00';
$order_today=$DB->getColumn("SELECT SUM(realmoney) from pre_order where uid={$pid} and tid<>2 and status=1 and endtime>='$today'");
if(!$order_today) $order_today = 0;
$enable_money=round($userrow['money']-$order_today,2);
if($enable_money<0)$enable_money=0;
}else{
$enable_money=$userrow['money'];
}
if(!$conf['transfer_rate'])$conf['transfer_rate'] = $conf['settle_rate'];
$result = ['code'=>0, 'available_money'=>strval($enable_money), 'transfer_rate'=>$conf['transfer_rate']];
return $result;
}
}
+171
View File
@@ -0,0 +1,171 @@
<?php
namespace lib;
class hieroglyphy{
private $characters;
private $numbers;
private $unescape;
private $functionConstructor;
public function __construct(){
$this->precharacters();
}
private function precharacters(){
$this->numbers = array(
"+[]",
"+!![]",
"!+[]+!![]",
"!+[]+!![]+!![]",
"!+[]+!![]+!![]+!![]",
"!+[]+!![]+!![]+!![]+!![]",
"!+[]+!![]+!![]+!![]+!![]+!![]",
"!+[]+!![]+!![]+!![]+!![]+!![]+!![]",
"!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]",
"!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]"
);
$this->characters = array(
"0" => "(" . $this->numbers[0] . "+[])",
"1" => "(" . $this->numbers[1] . "+[])",
"2" => "(" . $this->numbers[2] . "+[])",
"3" => "(" . $this->numbers[3] . "+[])",
"4" => "(" . $this->numbers[4] . "+[])",
"5" => "(" . $this->numbers[5] . "+[])",
"6" => "(" . $this->numbers[6] . "+[])",
"7" => "(" . $this->numbers[7] . "+[])",
"8" => "(" . $this->numbers[8] . "+[])",
"9" => "(" . $this->numbers[9] . "+[])"
);
$_object_Object = "[]+{}";
$_NaN = "+{}+[]";
$_true = "!![]+[]";
$_false = "![]+[]";
$_undefined = "[][[]]+[]";
$this->characters[" "] = "(" . $_object_Object . ")[" . $this->numbers[7] . "]";
$this->characters["["] = "(" . $_object_Object . ")[" . $this->numbers[0] . "]";
$this->characters["]"] = "(" . $_object_Object . ")[" . $this->characters[1] . "+" . $this->characters[4] . "]";
$this->characters["a"] = "(" . $_NaN . ")[" . $this->numbers[1] . "]";
$this->characters["b"] = "(" . $_object_Object . ")[" . $this->numbers[2] . "]";
$this->characters["c"] = "(" . $_object_Object . ")[" . $this->numbers[5] . "]";
$this->characters["d"] = "(" . $_undefined . ")[" . $this->numbers[2] . "]";
$this->characters["e"] = "(" . $_undefined . ")[" . $this->numbers[3] . "]";
$this->characters["f"] = "(" . $_false . ")[" . $this->numbers[0] . "]";
$this->characters["i"] = "(" . $_undefined . ")[" . $this->numbers[5] . "]";
$this->characters["j"] = "(" . $_object_Object . ")[" . $this->numbers[3] . "]";
$this->characters["l"] = "(" . $_false . ")[" . $this->numbers[2] . "]";
$this->characters["n"] = "(" . $_undefined . ")[" . $this->numbers[1] . "]";
$this->characters["o"] = "(" . $_object_Object . ")[" . $this->numbers[1] . "]";
$this->characters["r"] = "(" . $_true . ")[" . $this->numbers[1] . "]";
$this->characters["s"] = "(" . $_false . ")[" . $this->numbers[3] . "]";
$this->characters["t"] = "(" . $_true . ")[" . $this->numbers[0] . "]";
$this->characters["u"] = "(" . $_undefined . ")[" . $this->numbers[0] ."]";
$this->characters["N"] = "(" . $_NaN . ")[" . $this->numbers[0] . "]";
$this->characters["O"] = "(" . $_object_Object . ")[" . $this->numbers[8] . "]";
$_Infinity = "+(" . $this->numbers[1] . "+" . $this->characters["e"] . "+" . $this->characters[1] . "+" . $this->characters[0] . "+" . $this->characters[0] . "+" . $this->characters[0] . ")+[]";
$this->characters["y"] = "(" . $_Infinity . ")[" . $this->numbers[7] . "]";
$this->characters["I"] = "(" . $_Infinity . ")[" . $this->numbers[0] . "]";
$_1e100 = "+(" . $this->numbers[1] . "+" . $this->characters["e"] . "+" . $this->characters[1] . "+" . $this->characters[0] . "+" . $this->characters[0] . ")+[]";
$this->characters["+"] = "(" . $_1e100 . ")[" . $this->numbers[2] . "]";
$this->functionConstructor = "[][" . $this->hieroglyphyString("sort") . "][" . $this->hieroglyphyString("constructor") . "]";
//Below $this->characters need target http(s) pages
$locationString = "[]+" . $this->hieroglyphyScript("return location");
$this->characters["h"] = "(" . $locationString . ")" . "[" . $this->numbers[0] . "]";
$this->characters["p"] = "(" . $locationString . ")" . "[" . $this->numbers[3] . "]";
$this->characters["/"] = "(" . $locationString . ")" . "[" . $this->numbers[6] . "]";
$this->unescape = $this->hieroglyphyScript("return unescape");
$escape = $this->hieroglyphyScript("return escape");
$this->characters["%"] = $escape . "(" . $this->hieroglyphyString("[") . ")[" . $this->numbers[0] . "]";
}
private function getHexaString ($number, $digits) {
$string = bin2hex($number);
while (strlen($string) < $digits) {
$string = "0" . $string;
}
return $string;
}
private function getUnescapeSequence ($charCode) {
return $this->unescape . "(" .
$this->hieroglyphyString("%" . $this->getHexaString($charCode, 2)) . ")";
}
private function getHexaSequence ($charCode) {
return $this->hieroglyphyString("\\x" . $this->getHexaString($charCode, 2));
}
private function getUnicodeSequence ($charCode) {
return $this->hieroglyphyString("\\u" . $this->getHexaString($charCode, 4));
}
private function hieroglyphyCharacter ($char) {
$charCode = ord($char);
if (isset($this->characters[$char])) {
return $this->characters[$char];
}
if (($char == "\\") || ($char == "x")) {
//These chars must be handled appart becuase the others need them
$this->characters[$char] = $this->getUnescapeSequence($charCode);
return $this->characters[$char];
}
$shortestSequence = $this->getUnicodeSequence($charCode);
//ASCII $characters can be obtained with hexa and unscape sequences
if ($charCode < 128) {
$unescapeSequence = $this->getUnescapeSequence($charCode);
if (strlen($shortestSequence) > strlen($unescapeSequence)) {
$shortestSequence = $unescapeSequence;
}
$hexaSequence = $this->getHexaSequence($charCode);
if (strlen($shortestSequence) > strlen($hexaSequence)) {
$shortestSequence = $hexaSequence;
}
}
$this->characters[$char] = $shortestSequence;
return $shortestSequence;
}
public function hieroglyphyString ($str) {
$hieroglyphiedStr = "";
for ($i = 0; $i < strlen($str); $i++) {
$hieroglyphiedStr .= ($i > 0) ? "+" : "";
$hieroglyphiedStr .= $this->hieroglyphyCharacter($str[$i]);
}
return $hieroglyphiedStr;
}
public function hieroglyphyNumber ($n) {
$n = +$n;
if ($n <= 9) {
return $this->numbers[$n];
}
return "+(" . $this->hieroglyphyString(ord($n[10])) . ")";
}
public function hieroglyphyScript ($src) {
return $this->functionConstructor . "(" . $this->hieroglyphyString($src) . ")()";
}
}
+73
View File
@@ -0,0 +1,73 @@
<?php
namespace lib\mail;
class Aliyun
{
private $AccessKeyId;
private $AccessKeySecret;
function __construct($AccessKeyId, $AccessKeySecret)
{
$this->AccessKeyId = $AccessKeyId;
$this->AccessKeySecret = $AccessKeySecret;
}
private function aliyunSignature($parameters, $accessKeySecret, $method)
{
ksort($parameters);
$canonicalizedQueryString = '';
foreach ($parameters as $key => $value) {
if($value === null) continue;
$canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
}
$stringToSign = $method . '&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
$signature = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret . "&", true));
return $signature;
}
private function percentEncode($str)
{
$search = ['+', '*', '%7E'];
$replace = ['%20', '%2A', '~'];
return str_replace($search, $replace, urlencode($str));
}
public function send($to, $sub, $msg, $from, $from_name)
{
if (empty($this->AccessKeyId) || empty($this->AccessKeySecret)) return false;
$url = 'https://dm.aliyuncs.com/';
$data = array(
'Action' => 'SingleSendMail',
'AccountName' => $from,
'ReplyToAddress' => 'false',
'AddressType' => 1,
'ToAddress' => $to,
'FromAlias' => $from_name,
'Subject' => $sub,
'HtmlBody' => $msg,
'Format' => 'JSON',
'Version' => '2015-11-23',
'AccessKeyId' => $this->AccessKeyId,
'SignatureMethod' => 'HMAC-SHA1',
'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
'SignatureVersion' => '1.0',
'SignatureNonce' => random(8)
);
$data['Signature'] = $this->aliyunSignature($data, $this->AccessKeySecret, 'POST');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
$json = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$arr = json_decode($json, true);
if ($httpCode == 200) {
return true;
} else {
return $arr['Message'];
}
}
}
@@ -0,0 +1,2 @@
<?php
namespace lib\mail\PHPMailer; class Exception extends \Exception { public function errorMessage() { return '<strong>' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "</strong><br />\n"; } }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace lib\mail;
class Sendcloud {
private $apiUser;
private $apiKey;
function __construct($apiUser, $apiKey){
$this->apiUser = $apiUser;
$this->apiKey = $apiKey;
}
public function send($to, $sub, $msg, $from, $from_name){
if(empty($this->apiUser)||empty($this->apiKey))return false;
$url='http://api.sendcloud.net/apiv2/mail/send';
$data=array(
'apiUser' => $this->apiUser,
'apiKey' => $this->apiKey,
'from' => $from,
'fromName' => $from_name,
'to' => $to,
'subject' => $sub,
'html' => $msg);
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$json=curl_exec($ch);
curl_close($ch);
$arr=json_decode($json,true);
if($arr['statusCode']==200){
return true;
}else{
return implode("\n",$arr['message']);
}
}
}
+68
View File
@@ -0,0 +1,68 @@
<?php
namespace lib\sms;
class Aliyun
{
private $AccessKeyId;
private $AccessKeySecret;
function __construct($AccessKeyId, $AccessKeySecret)
{
$this->AccessKeyId = $AccessKeyId;
$this->AccessKeySecret = $AccessKeySecret;
}
private function aliyunSignature($parameters, $accessKeySecret, $method)
{
ksort($parameters);
$canonicalizedQueryString = '';
foreach ($parameters as $key => $value) {
if($value === null) continue;
$canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
}
$stringToSign = $method . '&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
$signature = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret . "&", true));
return $signature;
}
private function percentEncode($str)
{
$search = ['+', '*', '%7E'];
$replace = ['%20', '%2A', '~'];
return str_replace($search, $replace, urlencode($str));
}
public function send($phone, $param, $moban, $sign, $sitename)
{
if (empty($this->AccessKeyId) || empty($this->AccessKeySecret)) return false;
$url = 'https://dysmsapi.aliyuncs.com/';
$TemplateParam = json_encode($param);
$data = array(
'Action' => 'SendSms',
'PhoneNumbers' => $phone,
'SignName' => $sign,
'TemplateCode' => $moban,
'TemplateParam' => $TemplateParam,
'Format' => 'JSON',
'RegionId' => 'cn-hangzhou',
'Version' => '2017-05-25',
'AccessKeyId' => $this->AccessKeyId,
'SignatureMethod' => 'HMAC-SHA1',
'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
'SignatureVersion' => '1.0',
'SignatureNonce' => random(8)
);
$data['Signature'] = $this->aliyunSignature($data, $this->AccessKeySecret, 'POST');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
$json = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$arr = json_decode($json, true);
return $arr;
}
}
+86
View File
@@ -0,0 +1,86 @@
<?php
namespace lib\sms;
class Qcloud
{
private static $apiurl = 'https://yun.tim.qq.com/v5/tlssmssvr/sendsms';
private $appid;
private $appkey;
public function __construct($appid, $appkey)
{
$this->appid = $appid;
$this->appkey = $appkey;
}
/**
* 指定模板单发短信
* @param string $mobile 手机号码
* @param string $tpl_id 模板ID
* @param array $params 模板参数
* @param string $sign 签名内容
* @return bool
*/
public function send($mobile, $tpl_id, $params, $sign)
{
if (empty($this->appid) || empty($this->appkey)) return false;
$time = time();
$random = rand(100000, 999999);
$url = self::$apiurl . "?sdkappid=" . $this->appid . "&random=" . $random;
$data = [
'tel' => [
'nationcode' => '86',
'mobile' => $mobile
],
'params' => $params,
'time' => $time,
'tpl_id' => intval($tpl_id),
'sign' => $sign,
'sig' => $this->getSig($random, $time, $mobile),
];
try {
$res = $this->curlPost($url, json_encode($data));
$arr = json_decode($res, true);
return $arr;
} catch (\Exception $e) {
return ['result' => -1, 'errmsg' => $e->getMessage()];
}
}
//生成签名
private function getSig($random, $time, $mobile)
{
$signstr = 'appkey=' . $this->appkey . '&random=' . $random . '&time=' . $time . '&mobile=' . $mobile;
return hash("sha256", $signstr);
}
//发起POST请求
private function curlPost($url, $data)
{
$httpheader[] = "Accept: */*";
$httpheader[] = "Content-Type: application/json; charset=utf8";
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$res = curl_exec($ch);
if (curl_errno($ch) > 0) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new \Exception($errmsg);
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode != 200) {
throw new \Exception('http_code=' . $httpCode);
}
return $res;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace lib\sms;
class SmsBao {
private $user;
private $pass;
function __construct($user, $pass){
$this->user = $user;
$this->pass = $pass;
}
public function send($phone, $param, $moban, $sign){
if(empty($this->user)||empty($this->pass))return false;
$statusStr = array(
"0" => "短信发送成功",
"-1" => "参数不全",
"-2" => "服务器空间不支持",
"30" => "密码错误",
"40" => "账号不存在",
"41" => "余额不足",
"42" => "帐户已过期",
"43" => "IP地址限制",
"50" => "内容含有敏感词"
);
foreach($param as $k=>$v){
$moban = str_replace('{'.$k.'}',$v,$moban);
}
$content = '【'.$sign.'】'.$moban;
$sendurl = "http://api.smsbao.com/sms?u=".$this->user."&p=".md5($this->pass)."&m=".$phone."&c=".urlencode($content);
$result = get_curl($sendurl) ;
if ($result == '0'){
return true;
}else{
return isset($statusStr[$result])?$statusStr[$result]:('CODE:'.$result);
}
}
}
+228
View File
@@ -0,0 +1,228 @@
<?php
namespace lib\wechat;
use Exception;
class WeWorkAPI
{
private $wid;
private $accessToken;
public function __construct($id)
{
$this->wid = $id;
}
public function getAccessToken($force = false)
{
global $DB;
if(!empty($this->accessToken)) return $this->accessToken;
$DB->beginTransaction();
try{
$row = $DB->getRow("SELECT * FROM pre_wework WHERE id='{$this->wid}' LIMIT 1 FOR UPDATE");
if(!$row) throw new Exception('当前企业微信不存在');
if($row['access_token'] && strtotime($row['expiretime']) - 200 >= time() && !$force){
$DB->rollback();
$this->accessToken = $row['access_token'];
return $this->accessToken;
}
$corpId = $row['appid'];
$secret = $row['appsecret'];
$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=".$corpId."&corpsecret=".$secret;
$output = get_curl($url);
$res = json_decode($output, true);
if (isset($res['access_token'])) {
$this->accessToken = $res['access_token'];
$expire_time = time() + $res['expires_in'];
$DB->exec("UPDATE pre_wework SET access_token=:access_token,updatetime=NOW(),expiretime=:expiretime WHERE id=:id", [':access_token'=>$this->accessToken, ':expiretime'=>date("Y-m-d H:i:s", $expire_time), ':id'=>$this->wid]);
}elseif(isset($res['errmsg'])){
throw new Exception('AccessToken获取失败:'.$res['errmsg']);
}else{
throw new Exception('AccessToken获取失败');
}
$DB->commit();
return $this->accessToken;
}catch(Exception $e){
$DB->rollback();
throw $e;
}
}
//获取客服帐号列表
public function getKFList()
{
$accessToken = $this->getAccessToken();
$url = 'https://qyapi.weixin.qq.com/cgi-bin/kf/account/list?access_token='.$accessToken;
$post = ['offset'=>0, 'limit'=>100];
$response = get_curl($url, json_encode($post));
$result = json_decode($response, true);
if ($result['errcode'] == 0) {
return $result['account_list'];
}else{
throw new Exception('客服帐号列表获取失败:'.$result['errmsg']);
}
}
//获取微信客服链接
public function getKFURL($kfid, $scene)
{
$accessToken = $this->getAccessToken();
$url = 'https://qyapi.weixin.qq.com/cgi-bin/kf/add_contact_way?access_token='.$accessToken;
$post = ['open_kfid'=>$kfid, 'scene'=>$scene];
$response = get_curl($url, json_encode($post));
$result = json_decode($response, true);
if ($result['errcode'] == 0 && $result['url']) {
return $result['url'];
}else{
throw new Exception('微信客服链接获取失败:'.$result['errmsg']);
}
}
//读取消息
public function syncMsg($kfid, $token, $cursor = '')
{
$accessToken = $this->getAccessToken();
$url = 'https://qyapi.weixin.qq.com/cgi-bin/kf/sync_msg?access_token='.$accessToken;
$post = ['cursor'=>$cursor, 'token'=>$token, 'open_kfid'=>$kfid];
$response = get_curl($url, json_encode($post));
$result = json_decode($response, true);
if ($result['errcode'] == 0) {
return $result;
}else{
throw new Exception('客服消息列表获取失败:'.$result['errmsg']);
}
}
//加锁获取最新消息
public function lockGetMsg($kfid, $token)
{
global $DB;
$this->getAccessToken();
$DB->beginTransaction();
$wxkfaccount = $DB->getRow("SELECT `id`,`cursor` FROM pre_wxkfaccount WHERE openkfid=:openkfid LIMIT 1 FOR UPDATE", [':openkfid'=>$kfid]);
$cursor = $wxkfaccount['cursor'];
try{
$result = $this->syncMsg($kfid, $token, $cursor?$cursor:'');
}catch(Exception $e){
$DB->rollBack();
throw $e;
}
$cursor = $result['next_cursor'];
$DB->update('wxkfaccount', ['cursor'=>$cursor], ['id'=>$wxkfaccount['id']]);
$DB->commit();
return $result['msg_list'];
}
//发送消息
public function sendMsg($touser, $kfid, $msgtype, $msgparam)
{
$accessToken = $this->getAccessToken();
$url = 'https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token='.$accessToken;
$post = ['touser'=>$touser, 'open_kfid'=>$kfid, 'msgtype'=>$msgtype];
$post[$msgtype] = $msgparam;
$response = get_curl($url, json_encode($post));
$result = json_decode($response, true);
if ($result['errcode'] == 0) {
return $result['msgid'];
}else{
throw new Exception('发送消息失败:'.$result['errmsg']);
}
}
//发送文本消息
public function sendTextMsg($touser, $kfid, $content)
{
$param = ['content'=>$content];
return $this->sendMsg($touser, $kfid, 'text', $param);
}
//发送菜单消息
public function sendMenuMsg($touser, $kfid, $head_content, $list, $tail_content = '')
{
$param = ['head_content'=>$head_content, 'list'=>$list];
if($tail_content) $param['tail_content'] = $tail_content;
return $this->sendMsg($touser, $kfid, 'msgmenu', $param);
}
//发送欢迎消息
public function sendWelcomeMsg($code, $msgtype, $msgparam)
{
$accessToken = $this->getAccessToken();
$url = 'https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg_on_event?access_token='.$accessToken;
$post = ['code'=>$code, 'msgtype'=>$msgtype];
$post[$msgtype] = $msgparam;
$response = get_curl($url, json_encode($post));
$result = json_decode($response, true);
if ($result['errcode'] == 0) {
return $result['msgid'];
}else{
throw new Exception('发送消息失败:'.$result['errmsg']);
}
}
//发送欢迎文本消息
public function sendWelcomeTextMsg($code, $content)
{
$param = ['content'=>$content];
return $this->sendWelcomeMsg($code, 'text', $param);
}
//发送欢迎菜单消息
public function sendWelcomeMenuMsg($code, $head_content, $list, $tail_content = '')
{
$param = ['head_content'=>$head_content, 'list'=>$list];
if($tail_content) $param['tail_content'] = $tail_content;
return $this->sendWelcomeMsg($code, 'msgmenu', $param);
}
public function connect($appid, $callback, $agentid){
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize';
$param = [
"appid" => $appid,
"redirect_uri" => $callback,
"response_type" => "code",
"scope" => "snsapi_base",
"agentid" => $agentid
];
$url .= '?'.http_build_query($param)."#wechat_redirect";
header("Location: ".$url);
exit;
}
public function get_userinfo($code){
$accessToken = $this->getAccessToken();
$url = 'https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo';
$param = [
"access_token" => $accessToken,
"code" => $code
];
$url .= '?'.http_build_query($param);
$response = get_curl($url);
$arr = json_decode($response, true);
if(isset($arr['errcode']) && $arr['errcode'] == 0){
return $arr;
}else{
throw new Exception('获取用户信息失败 ['.$arr['errcode'].']'.$arr['errmsg']);
}
}
public function send_message($touser, $agentid, $msgtype, $msgparam){
$accessToken = $this->getAccessToken();
$url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token='.$accessToken;
$post = [
'touser' => $touser,
'agentid' => intval($agentid),
'msgtype' => $msgtype
];
$post[$msgtype] = $msgparam;
$response = get_curl($url, json_encode($post));
$result = json_decode($response, true);
if ($result['errcode'] == 0) {
return true;
}else{
throw new Exception('发送消息失败:'.$result['errmsg']);
}
}
}
+103
View File
@@ -0,0 +1,103 @@
<?php
namespace lib\wechat;
use Exception;
class WeWorkMsg
{
private $token;
private $crypt;
public function __construct($token, $aeskey)
{
global $conf;
$this->token = $token;
$this->crypt = new WechatCrypt($aeskey);
}
//验证URL有效性
public function verifyURL()
{
if (!$this->verifySignature($_GET['echostr'])) {
exit('签名验证失败');
}
$msg = $this->crypt->decrypt($_GET['echostr']);
if(!$msg) exit('消息解密失败');
exit($msg);
}
//获取回调的消息内容
public function getMessage()
{
$xml = file_get_contents('php://input');
$arr = $this->xml2array($xml);
if (!$arr) exit('消息体解析失败');
if (!$this->verifySignature($arr['Encrypt'])) {
exit('签名验证失败');
}
$msgtext = $this->crypt->decrypt($arr['Encrypt']);
if(!$msgtext) exit('消息解密失败');
$msg = $this->xml2array($msgtext);
return $msg;
}
//响应消息内容
public function responseMessage($array, $corpid)
{
$xml = $this->array2Xml($array);
$encrypted = $this->crypt->encrypt($xml, $corpid);
$timestamp = time();
$nonce = time();
$signature = $this->getSignature($timestamp, $nonce, $encrypted);
$array = [
'Encrypt' => $encrypted,
'MsgSignature' => $signature,
'TimeStamp' => $timestamp,
'Nonce' => $nonce
];
echo $this->array2Xml($array);
}
//验证回调签名
private function verifySignature($msg_encrypt)
{
if (!(isset($_GET['msg_signature']) && isset($_GET['timestamp']) && isset($_GET['nonce']))) {
return false;
}
$signature = $this->getSignature($_GET['timestamp'], $_GET['nonce'], $msg_encrypt);
return $signature === $_GET['msg_signature'];
}
//生成SHA1签名
private function getSignature($timestamp, $nonce, $encrypt_msg)
{
$signatureArray = array($encrypt_msg, $this->token, $timestamp, $nonce);
sort($signatureArray, SORT_STRING);
return sha1(implode($signatureArray));
}
//转为XML数据
private function array2Xml($data)
{
if (!is_array($data)) {
return false;
}
$xml = '<xml>';
foreach ($data as $key => $val) {
$xml .= (is_numeric($val) ? "<{$key}>{$val}</{$key}>" : "<{$key}><![CDATA[{$val}]]></{$key}>");
}
return $xml . '</xml>';
}
//解析XML数据
private function xml2array($xml)
{
if (!$xml) {
return false;
}
LIBXML_VERSION < 20900 && libxml_disable_entity_loader(true);
return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA), JSON_UNESCAPED_UNICODE), true);
}
}
+149
View File
@@ -0,0 +1,149 @@
<?php
namespace lib\wechat;
use Exception;
class WechatAPI
{
private $wid;
private $accessToken;
private $jsapiTicket;
public function __construct($id)
{
$this->wid = $id;
}
public function getAccessToken($force = false)
{
global $DB;
if(!empty($this->accessToken)) return $this->accessToken;
$DB->beginTransaction();
try{
$row = $DB->getRow("SELECT * FROM pre_weixin WHERE id='{$this->wid}' LIMIT 1 FOR UPDATE");
if(!$row) throw new Exception('记录不存在');
if($row['access_token'] && strtotime($row['expiretime']) - 200 >= time() && !$force){
$DB->rollback();
$this->accessToken = $row['access_token'];
return $this->accessToken;
}
$appid = $row['appid'];
$secret = $row['appsecret'];
$url = "https://api.weixin.qq.com/cgi-bin/stable_token";
$post = json_encode(['grant_type'=>'client_credential', 'appid'=>$appid, 'secret'=>$secret]);
$output = get_curl($url, $post);
$res = json_decode($output, true);
if (isset($res['access_token'])) {
$this->accessToken = $res['access_token'];
$expire_time = time() + $res['expires_in'];
$DB->exec("UPDATE pre_weixin SET access_token=:access_token,updatetime=NOW(),expiretime=:expiretime WHERE id=:id", [':access_token'=>$this->accessToken, ':expiretime'=>date("Y-m-d H:i:s", $expire_time), ':id'=>$this->wid]);
}elseif(isset($res['errmsg'])){
throw new Exception('AccessToken获取失败:'.$res['errmsg']);
}else{
throw new Exception('AccessToken获取失败');
}
$DB->commit();
return $this->accessToken;
}catch(Exception $e){
$DB->rollback();
throw $e;
}
}
public function generate_scheme($path, $query, $expire = 600)
{
$access_token = $this->getAccessToken();
$url = "https://api.weixin.qq.com/wxa/generatescheme?access_token=".$access_token;
$data = ['jump_wxa'=>['path'=>$path, 'query'=>$query]];
if($expire>0){
$data['is_expire'] = true;
$data['expire_time'] = time()+$expire;
}
$output = get_curl($url, json_encode($data));
$res = json_decode($output, true);
if ($res && $res['errcode'] == 0) {
return $res['openlink'];
}else{
throw new Exception('urlscheme生成失败:'.$res['errmsg']);
}
}
//发送微信公众号模板消息
public function sendTemplateMessage($openid, $template_id, $jumpurl, $data){
$access_token = $this->getAccessToken();
$url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='.$access_token;
$post = [
'touser' => $openid,
'template_id' => $template_id,
'url' => $jumpurl,
'data' => $data
];
$response = get_curl($url, json_encode($post));
$res = json_decode($response, true);
if ($res && $res['errcode'] == 0) {
return true;
}else{
throw new Exception('模板消息发送失败:'.$res['errmsg']);
}
}
public function getJsapiTicket($force = false)
{
global $CACHE;
if(!empty($this->jsapiTicket)) return $this->jsapiTicket;
$cachekey = 'wx_jsapi_ticket_'.$this->wid;
$row = $CACHE->read($cachekey);
if($row){
$row = unserialize($row);
if($row['ticket'] && strtotime($row['expiretime']) - 200 >= time() && !$force){
$this->jsapiTicket = $row['ticket'];
return $this->jsapiTicket;
}
}
$access_token = $this->getAccessToken();
$url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='.$access_token.'&type=jsapi';
$output = get_curl($url);
$res = json_decode($output, true);
if (isset($res['ticket'])) {
$this->jsapiTicket = $res['ticket'];
$expire_time = time() + $res['expires_in'];
$CACHE->save($cachekey, ['ticket'=>$this->jsapiTicket, 'expiretime'=>date("Y-m-d H:i:s", $expire_time)], $res['expires_in']);
}elseif(isset($res['errmsg'])){
throw new Exception('JsapiTicket获取失败:'.$res['errmsg']);
}else{
throw new Exception('JsapiTicket获取失败');
}
}
public function getJsapiConfig($appid, $url, $jsApiList, $debug = false)
{
$ticket = $this->getJsapiTicket();
$data = [
'jsapi_ticket' => $ticket,
'timestamp' => time(),
'noncestr' => random(16),
'url' => $url
];
$config = [
'debug' => $debug,
'appId' => $appid,
'timestamp' => $data['timestamp'],
'nonceStr' => $data['noncestr'],
'signature' => $this->getSignature($data),
'jsApiList' => $jsApiList
];
return $config;
}
public function getSignature($data)
{
ksort($data);
$params = array();
foreach ($data as $key => $value) {
$params[] = "{$key}={$value}";
}
return sha1(join('&', $params));
}
}
+77
View File
@@ -0,0 +1,77 @@
<?php
namespace lib\wechat;
class WechatCrypt
{
private $key;
private $iv;
private static $block_size = 32;
public function __construct($enckey)
{
$this->key = base64_decode($enckey . '=');
$this->iv = substr($this->key, 0, 16);
}
public function encrypt($data, $appid)
{
$str = $this->getRandomStr() . pack('N', strlen($data)) . $data . $appid;
$str = $this->enPKSC7($str);
$encrypted = openssl_encrypt($str, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $this->iv);
return $encrypted;
}
public function decrypt($data)
{
$decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $this->iv);
if(!$decrypted) return false;
$decrypted = $this->dePKSC7($decrypted);
$content = substr($decrypted, 16, strlen($decrypted));
$len_list = unpack('N', substr($content, 0, 4));
$xml_len = $len_list[1];
$xml_content = substr($content, 4, $xml_len);
$from_appid = substr($content, $xml_len + 4);
return $xml_content;
}
private function enPKSC7($text)
{
$block_size = self::$block_size; //128:16、256:32
$text_length = strlen($text);
//计算需要填充的位数
$amount_to_pad = $block_size - ($text_length % $block_size);
if ($amount_to_pad == 0) {
$amount_to_pad = $block_size;
}
//获得补位所用的字符
$pad_chr = chr($amount_to_pad);
$tmp = "";
for ($index = 0; $index < $amount_to_pad; $index++) {
$tmp .= $pad_chr;
}
return $text . $tmp;
}
private function dePKSC7($text)
{
$block_size = self::$block_size; //128:16、256:32
$pad = ord(substr($text, -1));
if ($pad < 1 || $pad > $block_size) {
$pad = 0;
}
return substr($text, 0, (strlen($text) - $pad));
}
private function getRandomStr()
{
$str = '';
$str_pol = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyl';
$max = strlen($str_pol) - 1;
for ($i = 0; $i < 16; $i++) {
$str .= $str_pol[mt_rand(0, $max)];
}
return $str;
}
}