first commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.'签名校验失败');
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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'=>'删除分账接收方成功'];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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'=>'删除分账接收方成功'];
|
||||
}
|
||||
}
|
||||
@@ -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/>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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'=>'删除分账接收方成功'];
|
||||
}
|
||||
}
|
||||
@@ -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'=>'删除分账接收方成功'];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) . ")()";
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user