This commit is contained in:
2025-03-26 21:22:37 +08:00
parent 960940fd25
commit e9d83351ea
15 changed files with 912 additions and 116 deletions

View File

@@ -58,9 +58,10 @@ class Mmodel
*/
static function catch($fn){
try{
Tools::log_to_write_txt(['input'=>input()]);
//不输出日志,此代码块可能用于内部逻辑
//Tools::log_to_write_txt(['input'=>input()]);
$res = $fn();
Tools::log_to_write_txt(['output'=>$res]);
//Tools::log_to_write_txt(['output'=>$res]);
return $res;
}catch (\Exception $e){
Tools::error_txt_log($e);
@@ -75,11 +76,11 @@ class Mmodel
* authorwh
* @param $fn
*/
static function catchJson($fn){
static function catchJson($fn, $is_whrite_log=true){
try{
Tools::log_to_write_txt(['input'=>input()]);
!$is_whrite_log?:Tools::log_to_write_txt(['input'=>input()]);
$res = $fn();
Tools::log_to_write_txt(['output'=>$res]);
!$is_whrite_log?:Tools::log_to_write_txt(['output'=>$res]);
return json($res);
}catch (\Exception $e){
Tools::error_txt_log($e);
@@ -94,12 +95,12 @@ class Mmodel
* authorwh
* @param $fn
*/
static function catchTrans($fn){
static function catchTrans($fn, $is_whrite_log=true){
Db::startTrans();
try{
Tools::log_to_write_txt(['input'=>input()]);
!$is_whrite_log?:Tools::log_to_write_txt(['input'=>input()]);
$res = $fn();
Tools::log_to_write_txt(['output'=>$res]);
!$is_whrite_log?:Tools::log_to_write_txt(['output'=>$res]);
Db::commit();
return $res;
}catch (\Exception $e){
@@ -116,12 +117,12 @@ class Mmodel
* authorwh
* @param $fn
*/
static function catchTransJson($fn){
static function catchTransJson($fn, $is_whrite_log=true){
Db::startTrans();
try{
Tools::log_to_write_txt(['input'=>input()]);
!$is_whrite_log?:Tools::log_to_write_txt(['input'=>input()]);
$res = $fn();
Tools::log_to_write_txt(['output'=>$res]);
!$is_whrite_log?:Tools::log_to_write_txt(['output'=>$res]);
Db::commit();
return json($res);
}catch (\Exception $e){

View File

@@ -0,0 +1,145 @@
<?php
/*
* description
* authorwh
* email
* createTime{2025/3/14} {16:12}
*/
namespace wanghua\general_utility_tools_php\alipay;
use wanghua\general_utility_tools_php\tool\Tools;
class AlipayAuthSDK extends BaseAlipay
{
/**
* desc获取支付宝用户授权信息
* authorwh
* @param $auth_code
* @return mixed
*/
public function getAuthInfo($auth_code){
if(session('session_alipay_system_oauth_token_response')){
//到期时间(s)
$expires_in = session('session_alipay_system_oauth_token_response.expires_in');
$auth_start = session('session_alipay_system_oauth_token_response.auth_start');
//这里减去600秒防止刷新token的时候时间还没到就过期了
if(strtotime($auth_start)+$expires_in-600<time()){
//过期了刷新token
$grantType = 'refresh_token';
$alipay_system_oauth_token_response = $this->authExchangeOpenid($auth_code,$grantType);
return $alipay_system_oauth_token_response;
}else{
return session('session_alipay_system_oauth_token_response');
}
}else{
//实时获取
$alipay_system_oauth_token_response = $this->authExchangeOpenid($auth_code);
return $alipay_system_oauth_token_response;
}
}
// 第一步构建授权URL (引导用户跳转)
function buildAuthUrl($auth_url)
{
//Tools::log_to_write_txt(['构建授权URL (引导用户跳转),$url'=>$auth_url]);
$redirect_uri = urlencode($auth_url); // 回调地址需在支付宝后台配置
$auth_url = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?" .
"app_id={$this->alipayConfig['app_id']}&" .
"scope=auth_user&" .
"redirect_uri={$redirect_uri}&" .
"state=meebo";//自定义防CSRF参数
//Tools::log_to_write_txt(['构建授权URL (引导用户跳转),$auth_url:'=>$auth_url]);
return $auth_url;
}
// 第二步:获取授权码
function authExchangeOpenid($auth_code,$grantType='authorization_code'){
$root_path = Tools::get_root_path();
require_once($root_path.'library/alipay-sdk-php-all/aop/AopCertClient.php'); // 支付宝官方SDK, 需从开放平台下载
//AlipaySystemOauthTokenRequest
require_once($root_path.'library/alipay-sdk-php-all/aop/request/AlipaySystemOauthTokenRequest.php');
/** 初始化 **/
$aop = new \AopCertClient;
/** 支付宝网关 **/
$aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";
/** 应用id,如何获取请参考https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
$aop->appId = $this->alipayConfig['app_id'];
/** 密钥格式为pkcs1如何获取私钥请参考https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
$aop->rsaPrivateKey = $this->alipayConfig['alipay_app_private_key'];
/** 应用公钥证书路径,下载后保存位置的绝对路径 **/
$appCertPath = $root_path.$this->alipayConfig['appCertPublicKey'];
/** 支付宝公钥证书路径,下载后保存位置的绝对路径 **/
$alipayCertPath = $root_path.$this->alipayConfig['cert_path_alipayCertPublicKey_RSA2'];
/** 支付宝公钥证书路径,下载后保存位置的绝对路径 **/
$rootCertPath = $root_path.$this->alipayConfig['cert_path_alipayRootCert'];
/** 设置签名类型 **/
$aop->signType= "RSA2";
/** 设置请求格式固定值json **/
$aop->format = "json";
/** 设置编码格式 **/
$aop->charset= "utf-8";
/** 调用getPublicKey从支付宝公钥证书中提取公钥 **/
$aop->alipayrsaPublicKey = $aop->getPublicKey($alipayCertPath);
/** 是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内 **/
$aop->isCheckAlipayPublicCert = true;
/** 调用getCertSN获取证书序列号 **/
$aop->appCertSN = $aop->getCertSN($appCertPath);
/** 调用getRootCertSN获取支付宝根证书序列号 **/
$aop->alipayRootCertSN = $aop->getRootCertSN($rootCertPath);
/** 实例化具体API对应的request类类名称和接口名称对应,当前调用接口名称alipay.system.oauth.token(换取授权访问令牌) **/
$request = new \AlipaySystemOauthTokenRequest ();
/** 值为authorization_code时代表用code换取值为refresh_token时代表用refresh_token换取 **/
$request->setGrantType($grantType);
/** 授权码用户对应用授权后得到可参考文档https://opendocs.alipay.com/open/284/web **/
$request->setCode($auth_code);//"4b203fe6c11548bcabd8da5bb087a83b"
/** 刷新令牌上次换取访问令牌时得到。见出参的refresh_token字段 **/
//$request->setRefreshToken("201208134b203fe6c11548bcabd8da5bb087a83b");
$result = $aop->execute ($request);
/**第三方调用服务商模式传值app_auth_token后会收款至授权token对应商家账号如何获传值app_auth_token请参考文档https://opensupport.alipay.com/support/helpcenter/79/201602494631 **/
//$result = $aop->execute ($request,null,$app_auth_token);
$json = json_encode($result,JSON_UNESCAPED_UNICODE);
//dump($json);;
//array(3) {
// ["alipay_system_oauth_token_response"] => array(6) {
// ["access_token"] => string(40) "authusrB61082f01b2064753b039210cec7ddB44"
// ["auth_start"] => string(19) "2025-03-14 14:59:02"
// ["expires_in"] => int(1296000)
// ["re_expires_in"] => int(2592000)
// ["refresh_token"] => string(40) "authusrB85949807a38d4bffbd5c86ae7e797B44"
// ["open_id"] => string(47) "0442qO88pZKcduCIdYq7Z4N8y29dGoocWheNow1jt_QW1k4"
// }
// ["alipay_cert_sn"] => string(32) "9cbb86296783f52af85119eb59308f9a"
// ["sign"] => string(344) "qTFAlIaq3DO3L+9cjoXVJVhSipib8v2ot0Vb1cFEDdtVUH99eZsd33vDBDaKobf00XhVUBqx9WbL67GfEbUF94s6cPfGn9kHuYSMDKh5VRCUFF9TI+melq6GAXih9FbsgqUTY/OuAxz5GDfYL974CppSi7+uBodl0KCmt9kC6VgoC0tUe0s8MDC7LRWBEXheAwrfzMn8NzCpbJRSWRfmewRnBzNXC3SVV6KrMlQPaNcj4Wjl9JQxxCOFXRGqeCMF7pDLYPrChFy7TOCVE/ONUbBQcR1p3qqek3MO/QhpeumTB33VsfKTMQOKjWhEEfSYJa7vGxkQBnZ5QVVngzGVHg=="
//}
$json_arr = json_decode($json,true);
$alipay_system_oauth_token_response = $json_arr['alipay_system_oauth_token_response'];
session('session_alipay_system_oauth_token_response',$alipay_system_oauth_token_response);
//$open_id = $alipay_system_oauth_token_response['open_id'];
return $alipay_system_oauth_token_response;
}
}

View File

@@ -0,0 +1,172 @@
<?php
/*
* description
* authorwh
* email
* createTime{2025/2/10} {10:11}
*/
namespace wanghua\general_utility_tools_php\alipay;
use Alipay\EasySDK\Kernel\Config;
use Alipay\EasySDK\Kernel\Factory;
use wanghua\general_utility_tools_php\alipay\transfer\AlipayTransfer;
use wanghua\general_utility_tools_php\alipay\transfer\TransferConfig;
use wanghua\general_utility_tools_php\tool\Tools;
/**
* 基础通用功能
*
* 说明:
* 支付和转账都能使用的功能
*
* Class BaseAlipay
* @package wanghua\general_utility_tools_php\alipay
*/
class BaseAlipay
{
protected array $alipayConfig = [];
public function __construct($alipayConfig)
{
$this->alipayConfig = $alipayConfig;
}
/**
* 查询支付宝账户余额
*/
function queryBalance(){
//$transferConfig = new TransferConfig();
//$transferConfig->cert_path_alipayCertPublicKey_RSA2 = Tools::get_root_path().$alipayConfig['cert_path_alipayCertPublicKey_RSA2'];//'<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->';
//$transferConfig->cert_path_alipayRootCert = Tools::get_root_path().$alipayConfig['cert_path_alipayRootCert'];//'<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->';
//$transferConfig->appCertPublicKey = Tools::get_root_path().$alipayConfig['appCertPublicKey'];//'<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->'
//$trans_obj = new AlipayTransfer();
Factory::setOptions($this->getAlipayOptions());
$method = 'alipay.fund.account.query';
//公共参数
$textParams = [
'app_id'=>$this->alipayConfig['app_id'],
'charset'=>'utf-8',
'sign_type'=>'RSA2',
'timestamp'=>Tools::get_now_date(),
'version'=>'1.0',
];
//请求参数
//订单号前缀
$biz_content = [
'account_type'=>'ACCTRANS_ACCOUNT',
];
$pay_res = Factory::util()->generic()->execute($method,$textParams,$biz_content);
return $pay_res;
}
/**
* desc证书模式参数非证书模式参数需单独获取
* authorwh
* @param array $this->alipayConfig 支付宝转账配置(非支付配置)
* @return Config
*/
function getAlipayOptions($notifyUrl='')
{
$root_path = Tools::get_root_path();
$options = new Config();
$options->protocol = 'https';
$options->gatewayHost = 'openapi.alipay.com';
$options->signType = 'RSA2';
//'<-- 请填写您的AppId例如2019022663440152 -->'
$options->appId = $this->alipayConfig['app_id'];//'2021002103639985';
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
$options->merchantPrivateKey = $this->alipayConfig['alipay_app_private_key'];//'<-- 请填写您的应用私钥例如MIIEvQIBADANB ... ... -->';
$options->alipayCertPath = $root_path.$this->alipayConfig['cert_path_alipayCertPublicKey_RSA2'];//'<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->';
$options->alipayRootCertPath = $root_path.$this->alipayConfig['cert_path_alipayRootCert'];//'<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->';
$options->merchantCertPath = $root_path.$this->alipayConfig['appCertPublicKey'];//'<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->';
//注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
// $options->alipayPublicKey = $this->alipayConfig['alipay_public_key'];//'<-- 请填写您的支付宝公钥例如MIIBIjANBg... -->';
//可设置异步通知接收服务地址(可选)
$options->notifyUrl = $notifyUrl;//"<-- 请填写您的支付类接口异步通知接收服务地址例如https://www.test.com/callback -->";
//可设置AES密钥调用AES加解密相关接口时需要可选
//$options->encryptKey = "<-- 请填写您的AES密钥例如aa4BtZ4tspm2wnXLb1ThQA== -->";
return $options;
}
/**
* 支付宝退款
*
* 注意:需要在正式服测,本地会报错
*
* doc:
* https://opendocs.alipay.com/open/3aea9b48_alipay.trade.refund?pathHash=4de421df&scene=common
*
* 测试结果:
* object(Alipay\EasySDK\Util\Generic\Models\AlipayOpenApiGenericResponse)#93 (7) {
["_name":protected] =&gt; array(5) {
["httpBody"] =&gt; string(9) "http_body"
["code"] =&gt; string(4) "code"
["msg"] =&gt; string(3) "msg"
["subCode"] =&gt; string(8) "sub_code"
["subMsg"] =&gt; string(7) "sub_msg"
}
["httpBody"] =&gt; string(826) "{"alipay_trade_refund_response":{"code":"10000","msg":"Success","buyer_logon_id":"150******25","fund_change":"Y","gmt_refund_pay":"2025-02-24 10:06:26","out_trade_no":"h5cqa31h1740360008389","refund_detail_item_list":[{"amount":"0.11","fund_channel":"ALIPAYACCOUNT"}],"refund_fee":"0.11","send_back_fee":"0.11","trade_no":"2025022422001457441416271979","buyer_open_id":"0442qO88pZKcduCIdYq7Z4N8y29dGoocWheNow1jt_QW1k4"},"alipay_cert_sn":"9cbb86296783f52af85119eb59308f9a","sign":"fcmu9CwYw0uziZTNImfGJvaYE9EdO4OoeKjktl/jxn+EGKvybDijKxTsn+jRM99jm9gcvmQmqweTd6OJMkep6cut1Tl5jsktYGy+ri1lLTGc9eNg+ctyO6qylnVaKQstV0QNZkuRo6Y36W3ZXolZk81ppNM1chtupsALHfwoWSirupqJ6Y52iBRG67kN0AxexL8mbOhwGS9vAMbMXoyRKJ7ajLGSmpnhb1sMvHVhFkvXaCBrzn6Nt1TMw6cyelqNHsAsmJ+OSnndVcRaqt9Q+IAwn98vhBhl1J5Vi7cWbsIYeki+TViQZ2ArW09IdBrP+A9qIydeM0BQdElRFWntvg=="}"
["code"] =&gt; string(5) "10000"
["msg"] =&gt; string(7) "Success"
["subCode"] =&gt; NULL
["subMsg"] =&gt; NULL
["_required":protected] =&gt; array(0) {
}
}
*/
function aliRefund($order_info){
$alipayConfig = $this->alipayConfig;
//$transferConfig = new TransferConfig();
//$transferConfig->cert_path_alipayCertPublicKey_RSA2 = Tools::get_root_path().$alipayConfig['cert_path_alipayCertPublicKey_RSA2'];//'<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->';
//$transferConfig->cert_path_alipayRootCert = Tools::get_root_path().$alipayConfig['cert_path_alipayRootCert'];//'<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->';
//$transferConfig->appCertPublicKey = Tools::get_root_path().$alipayConfig['appCertPublicKey'];//'<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->'
Factory::setOptions($this->getAlipayOptions());
$method = 'alipay.trade.refund';
//公共参数
$textParams = [
'app_id'=>$alipayConfig['app_id'],
'charset'=>'utf-8',
'sign_type'=>'RSA2',
'timestamp'=>Tools::get_now_date(),
'version'=>'1.0',
];
//请求参数 wap/pc/app支付
//【描述】退分账明细信息。
// 注: 1.当面付且非直付通模式无需传入退分账明细,系统自动按退款金额与订单金额的比率,
//从收款方和分账收入方退款,不支持指定退款金额与退款方。
// 2.直付通模式,电脑网站支付,手机 APP 支付,手机网站支付产品,须在退款请求中明确是否退分账,
//从哪个分账收入方退,退多少分账金额;
//如不明确,默认从收款方退款,收款方余额不足退款失败。不支持系统按比率退款。
$refund_royalty_parameters = [];//如果有分账,此项必填
//订单号前缀
$biz_content = [
//'account_type'=>'ACCTRANS_ACCOUNT',
'out_trade_no'=>$order_info['orderid'],
'refund_amount'=>$order_info['real_amount'],
];
if($refund_royalty_parameters){
$biz_content['refund_royalty_parameters'] = $refund_royalty_parameters;
}
$pay_res = Factory::util()->generic()->execute($method,$textParams,$biz_content);
return $pay_res;
}
}

View File

@@ -7,6 +7,7 @@
*/
namespace wanghua\general_utility_tools_php\alipay\pay;
use wanghua\general_utility_tools_php\alipay\BaseAlipay;
use wanghua\general_utility_tools_php\Mmodel;
use wanghua\general_utility_tools_php\tool\Tools;
@@ -17,15 +18,9 @@ use wanghua\general_utility_tools_php\tool\Tools;
* Class AlipayAppPay
* @package wanghua\general_utility_tools_php\alipay\pay
*/
class AlipayAppPay
class AlipayAppPay extends BaseAlipay
{
private $pay_config = [];
private $notifyUrl;
public function __construct($pay_config,$notifyUrl)
{
$this->pay_config = $pay_config;
$this->notifyUrl = $notifyUrl;
}
public $notifyUrl;
/**
* descapp支付

View File

@@ -18,6 +18,7 @@ use app\index\logic\CheckstandLogic;
use app\index\model\OrderModel;
use app\index\model\PartnerAccountModel;
use think\Db;
use wanghua\general_utility_tools_php\alipay\BaseAlipay;
use wanghua\general_utility_tools_php\phpmailer\Exception;
use wanghua\general_utility_tools_php\tool\Tools;
@@ -31,19 +32,9 @@ use wanghua\general_utility_tools_php\tool\Tools;
* Class AlipayScanPay
* @package wanghua\general_utility_tools_php\alipay\transfer
*/
class AlipayScanPay
class AlipayScanPay extends BaseAlipay
{
/**
* 支付参数配置
* @var array
*/
private array $config = [];
function __construct($config)
{
/** 设置支付参数 */
$this->config = $config;
}
/**
* desc面对面扫码支付-(扫用户的付款码)
@@ -88,37 +79,35 @@ class AlipayScanPay
/**
* desc获取支付配置
* authorwh
* @return Config
* @throws Exception
*/
private function getOptions()
{
if(empty($this->config)){
if(empty($this->pay_config)){
throw new Exception('支付宝配置错误');
}
if(empty($this->config['notifyUrl'])){
if(empty($this->pay_config['notifyUrl'])){
throw new Exception('支付宝配置错误notifyUrl通知地址字段必须配置免密支付是同步返回支付结果输入密码支付是异步通知支付结果');
}
$config = $this->config;
$options = new Config();
$options->protocol = 'https';
$options->gatewayHost = 'openapi.alipay.com';
$options->signType = $config['sign_type'];
$options->signType = $this->pay_config['sign_type'];
$options->appId = $config['app_id'];//'<-- 请填写您的AppId例如2019022663440152 -->';
$options->appId = $this->pay_config['app_id'];//'<-- 请填写您的AppId例如2019022663440152 -->';
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
$options->merchantPrivateKey = $config['alipay_app_private_key'];//'<-- 请填写您的应用私钥例如MIIEvQIBADANB ... ... -->';
$options->merchantPrivateKey = $this->pay_config['alipay_app_private_key'];//'<-- 请填写您的应用私钥例如MIIEvQIBADANB ... ... -->';
$options->alipayCertPath = Tools::get_root_path().$config['cert_path_alipayCertPublicKey_RSA2'];//'<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->';
$options->alipayRootCertPath = Tools::get_root_path().$config['cert_path_alipayRootCert'];//'<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->';
$options->merchantCertPath = Tools::get_root_path().$config['appCertPublicKey'];//'<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->';
$options->alipayCertPath = Tools::get_root_path().$this->pay_config['cert_path_alipayCertPublicKey_RSA2'];//'<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->';
$options->alipayRootCertPath = Tools::get_root_path().$this->pay_config['cert_path_alipayRootCert'];//'<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->';
$options->merchantCertPath = Tools::get_root_path().$this->pay_config['appCertPublicKey'];//'<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->';
//注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
// $options->alipayPublicKey = '<-- 请填写您的支付宝公钥例如MIIBIjANBg... -->';
//可设置异步通知接收服务地址(可选)
$options->notifyUrl = $this->config['notifyUrl'];//request()->domain().'/index/alipay/notify';//"<-- 请填写您的支付类接口异步通知接收服务地址例如https://www.test.com/callback -->";
$options->notifyUrl = $this->pay_config['notifyUrl'];//request()->domain().'/index/alipay/notify';//"<-- 请填写您的支付类接口异步通知接收服务地址例如https://www.test.com/callback -->";
return $options;
}
@@ -172,15 +161,15 @@ class AlipayScanPay
Tools::log_to_write_txt(['error'=>'trade_status为空,文件:'.__FILE__.',line:'.__LINE__]);
return '';
}
if(empty($this->config['seller_id'])){
if(empty($this->pay_config['seller_id'])){
Tools::log_to_write_txt(['error'=>'卖家seller_id为空,文件:'.__FILE__.',line:'.__LINE__]);
return '';
}
//判断来源
$seller_id = input('seller_id');
if($seller_id != $this->config['seller_id']){
Tools::log_to_write_txt(['error'=>'支付通知来源错误','seller_id'=>$seller_id,'config'=>$this->config['seller_id']]);
if($seller_id != $this->pay_config['seller_id']){
Tools::log_to_write_txt(['error'=>'支付通知来源错误','seller_id'=>$seller_id,'config'=>$this->pay_config['seller_id']]);
return 'fail';
}
//支付宝面对面扫码支付后续流程

View File

@@ -0,0 +1,271 @@
<?php
/*
* description
* authorwh
* email
* createTime{2025/2/24} {20:06}
*/
namespace wanghua\general_utility_tools_php\alipay\pay;
use wanghua\general_utility_tools_php\alipay\BaseAlipay;
use wanghua\general_utility_tools_php\tool\Tools;
/**
* 支付宝-手机网站支付
* Class AlipayWapPay
* @package wanghua\general_utility_tools_php\alipay\pay
*/
class AlipayWapPay extends BaseAlipay
{
/**
* desc移动端wap原生支付宝支付(证书模式-当系统存在转账和支付时,支付必须使用证书模式)
*
* 支付宝手机网站支付,高内聚,低耦合
* authorwh
*
* @return string html
*/
function alipayWapH5payCert($order,$notify_url,$pay_end_url){
$root_path = Tools::get_root_path();
require $root_path.'library/alipay-sdk-php-all/aop/AopCertClient.php';
require $root_path.'library/alipay-sdk-php-all/aop/request/AlipayTradeWapPayRequest.php';
Tools::log_to_write_txt(['支付宝支付(证书模式)-提交支付,参数(出参在回调中)', $order,$notify_url,$pay_end_url]);
//商户订单号,商户网站订单系统中唯一订单号,必填
$orderid = $order['orderid'];
$total_amount = $order['real_amount'];//交易金额
$subject = $order['goods_name']?:"购物消费¥{$total_amount}";//订单标题
//$game_admin_domain = any_sys_env_domain_conf('store_outer_api_domain');
//这里可以把支付结果通知到其它系统
//$notify_url = $game_admin_domain.'/paytool/Alipay/alipayNotify';
//跳转到支付结果并显示商品推荐
//$pay_end_url = url('paytool/recommend/payend','',false,true);//支付结果展示
//$alipayConfig = aliPayConfPublicAcc();
$alipayConfig = $this->alipayConfig;
/** 初始化 **/
$aop = new \AopCertClient();
/** 支付宝网关 **/
$aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";
/** 应用id,如何获取请参考https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
$aop->appId = $alipayConfig['app_id'];
/** 密钥格式为pkcs1如何获取私钥请参考https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
$aop->rsaPrivateKey = $alipayConfig['alipay_app_private_key'];
/** 应用公钥证书路径,下载后保存位置的绝对路径 **/
$appCertPath = $root_path.$alipayConfig['appCertPublicKey'];
/** 支付宝公钥证书路径,下载后保存位置的绝对路径 **/
$alipayCertPath = $root_path.$alipayConfig['cert_path_alipayCertPublicKey_RSA2'];
/** 支付宝公钥证书路径,下载后保存位置的绝对路径 **/
$rootCertPath = $root_path.$alipayConfig['cert_path_alipayRootCert'];
/** 设置签名类型 **/
$aop->signType= "RSA2";
/** 设置请求格式固定值json **/
$aop->format = "json";
/** 设置编码格式 **/
$aop->charset= "utf-8";
/** 调用getPublicKey从支付宝公钥证书中提取公钥 **/
$aop->alipayrsaPublicKey = $aop->getPublicKey($alipayCertPath);
/** 是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内 **/
$aop->isCheckAlipayPublicCert = true;
/** 调用getCertSN获取证书序列号 **/
$aop->appCertSN = $aop->getCertSN($appCertPath);
/** 调用getRootCertSN获取支付宝根证书序列号 **/
$aop->alipayRootCertSN = $aop->getRootCertSN($rootCertPath);
/** 实例化具体API对应的request类类名称和接口名称对应当前调用接口名称alipay.trade.wap.pay **/
$request = new \AlipayTradeWapPayRequest();
/** 设置业务参数 **/
$request->setBizContent("{" .
/** 商户订单号商户自定义需保证在商户端不重复20150320010101001 **/
"'out_trade_no':'$orderid'," .
/** 销售产品码,固定值QUICK_WAP_WAY **/
"'product_code':'QUICK_WAP_WAY'," .
/** 订单金额,精确到小数点后两位 **/
"'total_amount':'$total_amount'," .
/** 订单标题 **/
"'subject':'$subject'," .
/** 业务扩展参数 **/
// "'extend_params':{" .
/** 系统商编号填写服务商的PID用于获取返佣返佣参数传值前提传值账号需要签约返佣协议用于isv商户。 **/
//"'sys_service_provider_id':'2088511833207846'," .
/** 花呗分期参数传值前提:必须有该接口花呗收款准入条件,且需签约花呗分期 **/
/** 指定可选期数只支持3/6/12期还款期数越长手续费越高 **/
// "'hb_fq_num':'3'," .
/** 指定花呗分期手续费承担方式手续费可以由用户全承担该值为0也可以商户全承担该值为100但不可以共同承担即不可取0和100外的其他值。 **/
//"'hb_fq_seller_percent':'100'" .
// "}," .
/** 订单描述 **/
"'body':'$subject'" .
"}");
/**注:支付结果以异步通知为准,不能以同步返回为准,因为如果实际支付成功,但因为外力因素,如断网、断电等导致页面没有跳转,则无法接收到同步通知;**/
/** 支付完成的跳转地址,用于用户视觉感知支付已成功传值外网可以访问的地址如果同步未跳转可参考该文档进行确认https://opensupport.alipay.com/support/helpcenter/193/201602474937 **/
$request->setReturnUrl($pay_end_url);
/** 异步通知地址以http或者https开头的商户外网可以post访问的异步地址用于接收支付宝返回的支付结果如果未收到该通知可参考该文档进行确认https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/
$request->setNotifyUrl($notify_url);
/** 调用SDK生成支付链接可在浏览器打开链接进入支付页面 **/
$result = $aop->pageExecute ($request,'get');
/**第三方调用服务商模式传值app_auth_token后会收款至授权token对应商家账号如何获传值app_auth_token请参考文档https://opensupport.alipay.com/support/helpcenter/79/201602494631 **/
//$result = $aop->pageExecute($request,'get',"传入获取到的app_auth_token值");
/** 获取接口调用结果如果调用失败可根据返回错误信息到该文档寻找排查方案https://opensupport.alipay.com/support/helpcenter/93 **/
//print_r(htmlspecialchars($result));
$html = <<<EOF
<html><head></head><body style="display: none" onload="javascript:location.href='$result';"></body></html>
EOF;
return $html;
}
function alipayWapH5payCertReturnUrl($order,$notify_url,$pay_end_url){
$root_path = Tools::get_root_path();
require $root_path.'library/alipay-sdk-php-all/aop/AopCertClient.php';
require $root_path.'library/alipay-sdk-php-all/aop/request/AlipayTradeWapPayRequest.php';
Tools::log_to_write_txt(['支付宝支付(证书模式)-提交支付,参数(出参在回调中)', $order,$notify_url,$pay_end_url]);
//商户订单号,商户网站订单系统中唯一订单号,必填
$orderid = $order['orderid'];
$total_amount = $order['real_amount'];//交易金额
$subject = $order['goods_name']?:"购物消费¥{$total_amount}";//订单标题
//$game_admin_domain = any_sys_env_domain_conf('store_outer_api_domain');
//这里可以把支付结果通知到其它系统
//$notify_url = $game_admin_domain.'/paytool/Alipay/alipayNotify';
//跳转到支付结果并显示商品推荐
//$pay_end_url = url('paytool/recommend/payend','',false,true);//支付结果展示
//$alipayConfig = aliPayConfPublicAcc();
$alipayConfig = $this->alipayConfig;
/** 初始化 **/
$aop = new \AopCertClient();
/** 支付宝网关 **/
$aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";
/** 应用id,如何获取请参考https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
$aop->appId = $alipayConfig['app_id'];
/** 密钥格式为pkcs1如何获取私钥请参考https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
$aop->rsaPrivateKey = $alipayConfig['alipay_app_private_key'];
/** 应用公钥证书路径,下载后保存位置的绝对路径 **/
$appCertPath = $root_path.$alipayConfig['appCertPublicKey'];
/** 支付宝公钥证书路径,下载后保存位置的绝对路径 **/
$alipayCertPath = $root_path.$alipayConfig['cert_path_alipayCertPublicKey_RSA2'];
/** 支付宝公钥证书路径,下载后保存位置的绝对路径 **/
$rootCertPath = $root_path.$alipayConfig['cert_path_alipayRootCert'];
/** 设置签名类型 **/
$aop->signType= "RSA2";
/** 设置请求格式固定值json **/
$aop->format = "json";
/** 设置编码格式 **/
$aop->charset= "utf-8";
/** 调用getPublicKey从支付宝公钥证书中提取公钥 **/
$aop->alipayrsaPublicKey = $aop->getPublicKey($alipayCertPath);
/** 是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内 **/
$aop->isCheckAlipayPublicCert = true;
/** 调用getCertSN获取证书序列号 **/
$aop->appCertSN = $aop->getCertSN($appCertPath);
/** 调用getRootCertSN获取支付宝根证书序列号 **/
$aop->alipayRootCertSN = $aop->getRootCertSN($rootCertPath);
/** 实例化具体API对应的request类类名称和接口名称对应当前调用接口名称alipay.trade.wap.pay **/
$request = new \AlipayTradeWapPayRequest();
/** 设置业务参数 **/
$request->setBizContent("{" .
/** 商户订单号商户自定义需保证在商户端不重复20150320010101001 **/
"'out_trade_no':'$orderid'," .
/** 销售产品码,固定值QUICK_WAP_WAY **/
"'product_code':'QUICK_WAP_WAY'," .
/** 订单金额,精确到小数点后两位 **/
"'total_amount':'$total_amount'," .
/** 订单标题 **/
"'subject':'$subject'," .
/** 业务扩展参数 **/
// "'extend_params':{" .
/** 系统商编号填写服务商的PID用于获取返佣返佣参数传值前提传值账号需要签约返佣协议用于isv商户。 **/
//"'sys_service_provider_id':'2088511833207846'," .
/** 花呗分期参数传值前提:必须有该接口花呗收款准入条件,且需签约花呗分期 **/
/** 指定可选期数只支持3/6/12期还款期数越长手续费越高 **/
// "'hb_fq_num':'3'," .
/** 指定花呗分期手续费承担方式手续费可以由用户全承担该值为0也可以商户全承担该值为100但不可以共同承担即不可取0和100外的其他值。 **/
//"'hb_fq_seller_percent':'100'" .
// "}," .
/** 订单描述 **/
"'body':'$subject'" .
"}");
/**注:支付结果以异步通知为准,不能以同步返回为准,因为如果实际支付成功,但因为外力因素,如断网、断电等导致页面没有跳转,则无法接收到同步通知;**/
/** 支付完成的跳转地址,用于用户视觉感知支付已成功传值外网可以访问的地址如果同步未跳转可参考该文档进行确认https://opensupport.alipay.com/support/helpcenter/193/201602474937 **/
$request->setReturnUrl($pay_end_url);
/** 异步通知地址以http或者https开头的商户外网可以post访问的异步地址用于接收支付宝返回的支付结果如果未收到该通知可参考该文档进行确认https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/
$request->setNotifyUrl($notify_url);
/** 调用SDK生成支付链接可在浏览器打开链接进入支付页面 **/
$result = $aop->pageExecute ($request,'get');
/**第三方调用服务商模式传值app_auth_token后会收款至授权token对应商家账号如何获传值app_auth_token请参考文档https://opensupport.alipay.com/support/helpcenter/79/201602494631 **/
//$result = $aop->pageExecute($request,'get',"传入获取到的app_auth_token值");
/** 获取接口调用结果如果调用失败可根据返回错误信息到该文档寻找排查方案https://opensupport.alipay.com/support/helpcenter/93 **/
//print_r(htmlspecialchars($result));
// $html = <<<EOF
//<html><head></head><body style="display: none" onload="javascript:location.href='$result';"></body></html>
//EOF;
return $result;
}
}

View File

@@ -10,6 +10,7 @@ namespace wanghua\general_utility_tools_php\alipay\transfer;
use Alipay\EasySDK\Kernel\Config;
use Alipay\EasySDK\Kernel\Factory;
use wanghua\general_utility_tools_php\alipay\BaseAlipay;
use wanghua\general_utility_tools_php\tool\Tools;
/**
@@ -29,15 +30,14 @@ use wanghua\general_utility_tools_php\tool\Tools;
* 支付宝开放平台可能有多个应用,可能存在一个默认应用(应用名称:应用2.0签约2020102692466480),转账配置就用此应用的参数,而不是其它应用的配置!
*
*/
class AlipayTransfer
class AlipayTransfer extends BaseAlipay
{
/**
* desc转账到支付宝证书模式
* authorwh
* @param array $alipayConfig
* @param $transferConfig TransferConfig.php
* @param $transferData TransferConfig.php
* @return mixed
*
* 使用案例:
@@ -62,9 +62,9 @@ class AlipayTransfer
$trans_config->remark = $trans_data['remark'];//支付备注 可选
$trans = new AlipayTransfer();
$trans = new AlipayTransfer($alipayConfig);
Tools::log_to_write_txt(['转账到支付宝,入参:'=>input(), 'trans_config'=>$trans_config]);
$pay_res = $trans->alitransfer($alipayConfig, $trans_config);
$pay_res = $trans->alitransfer($trans_config);
Tools::log_to_write_txt(['转账到支付宝,出参:'=>$pay_res]);
//直接返回转账结果自主验证成功失败的status。code=10000表示操作成功status=SUCCESS表示转账成功
//由于是同步响应,所以不需要对结果验签
@@ -72,72 +72,37 @@ class AlipayTransfer
}
*
*/
function alitransfer(array $alipayConfig, $transferConfig){
//$transferConfig = new TransferConfig();
Factory::setOptions($this->getAlipayOptions($alipayConfig, $transferConfig));
function alitransfer($transferData){
Factory::setOptions($this->getAlipayOptions());
$method = 'alipay.fund.trans.uni.transfer';
//公共参数
$textParams = [
'app_id'=>$alipayConfig['app_id'],
'app_id'=>$this->alipayConfig['app_id'],
'charset'=>'utf-8',
'sign_type'=>'RSA2',
'timestamp'=>$transferConfig->timestamp,
'timestamp'=>$transferData->timestamp,
'version'=>'1.0',
];
//请求参数
//订单号前缀
$biz_content = [
'out_biz_no'=>$transferConfig->order_id,//商家支付订单号
'trans_amount'=>$transferConfig->trans_amount,
'out_biz_no'=>$transferData->order_id,//商家支付订单号
'trans_amount'=>$transferData->trans_amount,
'product_code'=>'TRANS_ACCOUNT_NO_PWD',
'biz_scene'=>'DIRECT_TRANSFER',
'order_title'=>$transferConfig->order_title,
'order_title'=>$transferData->order_title,
'payee_info'=>[
'identity'=>$transferConfig->phone,//手机号
'identity'=>$transferData->phone,//手机号
'identity_type'=>'ALIPAY_LOGON_ID',
'name'=>$transferConfig->name,//参与方真实姓名如果非空将校验收款支付宝账号姓名一致性。当identity_type=ALIPAY_LOGON_ID时本字段必填。
'name'=>$transferData->name,//参与方真实姓名如果非空将校验收款支付宝账号姓名一致性。当identity_type=ALIPAY_LOGON_ID时本字段必填。
],
'remark'=>$transferConfig->remark,
'remark'=>$transferData->remark,
];
$pay_res = Factory::util()->generic()->execute($method,$textParams,$biz_content);
return $pay_res;
}
/**
* desc证书模式参数非证书模式参数需单独获取
* authorwh
* @param array $alipayConfig 支付宝转账配置(非支付配置)
* @return Config
*/
protected function getAlipayOptions(array $alipayConfig, $transferConfig)
{
$options = new Config();
$options->protocol = 'https';
$options->gatewayHost = 'openapi.alipay.com';
$options->signType = 'RSA2';
//'<-- 请填写您的AppId例如2019022663440152 -->'
$options->appId = $alipayConfig['app_id'];//'2021002103639985';
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
$options->merchantPrivateKey = $alipayConfig['alipay_app_private_key'];//'<-- 请填写您的应用私钥例如MIIEvQIBADANB ... ... -->';
$options->alipayCertPath = $transferConfig->cert_path_alipayCertPublicKey_RSA2;//'<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->';
$options->alipayRootCertPath = $transferConfig->cert_path_alipayRootCert;//'<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->';
$options->merchantCertPath = $transferConfig->appCertPublicKey;//'<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->';
//注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
// $options->alipayPublicKey = $alipayConfig['alipay_public_key'];//'<-- 请填写您的支付宝公钥例如MIIBIjANBg... -->';
//可设置异步通知接收服务地址(可选)
$options->notifyUrl = $transferConfig->notifyUrl;//"<-- 请填写您的支付类接口异步通知接收服务地址例如https://www.test.com/callback -->";
//可设置AES密钥调用AES加解密相关接口时需要可选
//$options->encryptKey = "<-- 请填写您的AES密钥例如aa4BtZ4tspm2wnXLb1ThQA== -->";
return $options;
}
}

View File

@@ -21,6 +21,7 @@ use wanghua\general_utility_tools_php\tool\Tools;
*/
class ApiDocument
{
public $app_name = 'api';
private $api_cache_arr = [];//缓存所有接口
public $api_domain = 'http://127.0.0.1:8080/';//接口域名/ip
/**
@@ -46,7 +47,7 @@ class ApiDocument
public function __construct($api_domain='',$controllerDirectory='')
{
//默认如果是tp6那application就要改为app了自行传参吧
$this->controllerDirectory = Tools::get_root_path().'application/api/controller';
$this->controllerDirectory = Tools::get_root_path()."application/{$this->app_name}/controller";
if($api_domain){
$this->api_domain = $api_domain;
}
@@ -156,7 +157,7 @@ EOF;
if($methodName == '__construct'){
return '';
}
$api_url = "/api/{$className}/{$methodName}";
$api_url = "/{$this->app_name}/{$className}/{$methodName}";
$js_api_func_name = "api_{$className}_{$methodName}";
$str = <<<EOF
@@ -171,7 +172,7 @@ EOF;
$className = $this->camelCaseToUnderscore($className);
$api_name = "api/{$className}/{$methodName}";
$api_name = "{$this->app_name}/{$className}/{$methodName}";
$doc_txt = <<<EOF
* $api_name
*/
@@ -206,18 +207,25 @@ EOF;
.txt-lf{text-align: left}
</style>
<div style="width: 50%;margin: 0 auto;color: red;text-align: center;">
<div class="txt-lf">文档说明:</div>
<div class="txt-lf">1、如果没有明确说明提交请求均使用post</div>
<div class="txt-lf">2、此接口文档不包含websocket接口</div>
<div class="txt-lf">3、接口参数之间使用“/”符号隔开</div>
<div class="txt-lf">4、此文档接口测试功能只针对普通post、get接口不能测试文件上传或文件流</div>
<div class="txt-lf">5、功能模块按照颜色分组</div>
<div class="txt-lf" style="color: black;">清理缓存:
<div class="txt-lf">文档说明:</div>
<div class="txt-lf">1、如果没有明确说明提交请求均使用post</div>
<div class="txt-lf">2、此接口文档不包含websocket接口</div>
<div class="txt-lf">3、接口参数之间使用“/”符号隔开</div>
<div class="txt-lf">4、此文档接口测试功能只针对普通post、get接口不能测试文件上传或文件流</div>
<div class="txt-lf">5、功能模块按照颜色分组</div>
<div class="txt-lf" style="color: black;">清理缓存:
<a href='JavaScript:;' onclick="CacheObj.clearCache()">
点击清理
</a><span style="color: gray;font-size: 12px;">(由于接口数据可能会被缓存,发现数据没变化或需要时,可清理缓存)</span>
</div>
<div class="txt-lf">
<a href="/api_docs/api_list.html" style="margin: 20px">api应用文档</a>
<a href="/api_docs/{$this->app_name}_list.html" style="margin: 20px">{$this->app_name}应用文档</a>
</div>
</div>
EOF;
$script_str = "";

View File

@@ -31,7 +31,7 @@ class SystemException extends Handle
Tools::log_to_write_txt([
'error'=>'系统错误.'.$e->getMessage(),
'input'=>Request::instance()->input(),
'input'=>input(),
'error_info'=>$e->getTraceAsString()
]);

View File

@@ -118,8 +118,8 @@ class AliCloudChatGPT extends BaseChat
$this->messages[] = ["role" => "user", "content" => $question];
}
$post_msg_body['messages'] = $this->messages;
$postData = json_encode($post_msg_body);
$this->post_msg_body = $post_msg_body;
$postData = json_encode($post_msg_body);
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);

View File

@@ -55,6 +55,14 @@ class ChatGPT extends BaseChat
}
}
/**
* desc对话仅流式输出时调用该方法
* authorwh
* @param string $question
* @param array $config
* @param $answer_json_arr
* @return string
*/
function chat($question = '', $config = [], &$answer_json_arr)
{
$answer = '';
@@ -69,6 +77,15 @@ class ChatGPT extends BaseChat
return $answer;
}
/**
* @deprecated 废弃,因其不兼容故废弃
* desc非流式请求对话一次返回结果
* authorwh
* @param string $question
* @param array $config
* @param $answer_json_arr
* @return string
*/
function returnAnswer($question = '', $config = [], &$answer_json_arr)
{
$answer = '';
@@ -80,6 +97,14 @@ class ChatGPT extends BaseChat
return $answer;
}
/**
* @deprecated 废弃
* desc一般未使用
* authorwh
* @param string $question
* @param array $config
* @param $callback
*/
private function curlPostChat($question = '', $config = [], $callback)
{
$url = $this->url;
@@ -96,8 +121,8 @@ class ChatGPT extends BaseChat
$this->messages[] = ["role" => "user", "content" => $question];
}
$post_msg_body['messages'] = $this->messages;
$postData = json_encode($post_msg_body);
$this->post_msg_body = $post_msg_body;
$postData = json_encode($post_msg_body);
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
@@ -110,6 +135,13 @@ class ChatGPT extends BaseChat
curl_exec($ch);
}
/**
* desc 获取对话结果,非流式输出时调用该方法
* authorwh
* @param string $question
* @param array $config
* @return array
*/
function getchatgptresponse($question = '', $config = [])
{
$url = $this->url;
@@ -126,12 +158,16 @@ class ChatGPT extends BaseChat
$this->messages[] = ["role" => "user", "content" => $question];
}
$post_msg_body['messages'] = $this->messages;
$this->post_msg_body = $post_msg_body;
$post_msg_body = json_encode($post_msg_body);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_msg_body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 忽略 SSL 证书验证
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
if (curl_error($ch)) {
return ['code' => curl_errno($ch), 'msg' => curl_error($ch)];

View File

@@ -139,7 +139,6 @@ class Curl
}
/**
* @deprecated 弃用
* GET
*
* authorwh
@@ -189,7 +188,6 @@ class Curl
}
}
/**
* @deprecated 弃用
* POST 表单
*
* authorwh
@@ -247,6 +245,44 @@ class Curl
}
}
/**
* 触发即忘的异步HTTP请求无需等待响应
*
* 环境:[linux]
*
* @param string $url 目标URL
* @param array $data POST数据可选
*/
static function asyncPostWithPopen(string $url, array $data = [])
{
$escapedUrl = escapeshellarg($url);
$postData = !empty($data) ? ' -d ' . escapeshellarg(http_build_query($data)) : '';
// 构建命令nohup 确保脱离终端)
$cmd = sprintf(
'nohup curl -s -X POST %s %s > /dev/null 2>&1 </dev/null &',
$escapedUrl,
$postData
);
$descriptors = [
0 => ['file', '/dev/null', 'r'],
1 => ['file', '/dev/null', 'w'],
2 => ['file', '/dev/null', 'w'],
];
$proc = proc_open($cmd, $descriptors, $pipes, null, null, ['bypass_shell' => false]);
if (!is_resource($proc)) {
Tools::log_to_write_txt('异步请求启动失败: ' . $cmd);
return false;
}
// 非阻塞关闭
proc_get_status($proc);
proc_close($proc);
return true;
}
/**
* @deprecated 弃用
* POST 查询参数

View File

@@ -0,0 +1,144 @@
<?php
/*
* description
* authorwh
* email
* createTime{2025/3/6} {14:02}
*/
namespace wanghua\general_utility_tools_php\tool;
/**
* ai生成音频
* Class AudioAiTool
* @package app\api\logic
*/
class AudioAiTool
{
private $ai_config = [];
public function __construct($ai_config)
{
$this->ai_config = $ai_config;
}
/**
* desc阶跃AI生成音频
*
*
* authorwh
* $audio_file_name 生成的音频文件名推荐使用用户唯一id默认为当前时间戳
*
* doc: https://platform.stepfun.com/docs/llm/audio
*
* 使用示例:
$txt = input('txt','收款到账12.03元!支付后有惊喜哦!~');
$phone = input('phone');
$ai_config = config('step_fun_ai_config');
$ai_config['model'] = 'step-tts-mini';
$ai_config['voice'] = 'jilingshaonv';//'yuanqinansheng';
$ai_config['speed'] = 1.1;
$ai_config['volume'] = 1.5;//可选值为 0.1~2.0 ,代表着将音量缩小至 10% ~ 增大至 200%(两倍音量)
//音频文件名称
$audio_file_name = "/partner/payment_audio/".$phone;
$res = (new AudioAiTool($ai_config))->stepfunBuildAudioMp3($txt,$audio_file_name);
if($res['code'] != 200){
return Tools::set_fail('生成音频失败');
}
$url = request()->domain().'/'.$res['data']['rel'];
echo "<a target='_blank' href='{$url}'>点击</a>";die;
//return Tools::set_ok('ok',['url'=>$url]);
*/
public function stepfunBuildAudioMp3(string $txt,$audio_file_name = ''){
$url = $this->ai_config['base_url']?:'https://api.stepfun.com/v1/audio/speech';
$apiKey = $this->ai_config['APIKey'];//'KJS9PN05iwG9peJpPHW2y8uBHDLTEu6B6e1xIsA4QSxhVEn2DV7kMQeoWD4H2ecA';
//speed 参数,可选值为 0.5-2 ,代表着将语速降速为之前的一半 ~ 提速至两倍
$data = [
'model' => $this->ai_config['model']?:'step-tts-mini',
'input' => $txt?:'智能阶跃,十倍每一个人的可能',
'voice' => $this->ai_config['voice']?:'cixingnansheng',
'speed' => $this->ai_config['speed']?:1,
];
$headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey,
];
$dir_arr = $this->createMp3Dir($audio_file_name);
if(empty($dir_arr)){
return Tools::set_fail('生成音频失败');
}
$real_path = $dir_arr[0];//物理路径
$rel_url = $dir_arr[1];//相对路径
$result = $this->curlPost($url, $data, $headers, false);
// 将响应内容保存为 MP3 文件
if ($result !== false) {
// 尝试写入文件
if (file_put_contents($real_path, $result)) {
//echo "音频文件已保存为:{$filename} <a target='_blank' href='/{$rel}'>访问</a>\n";
return Tools::set_ok('ok',['rel'=>$rel_url]);
} else {
//echo "写入文件 {$filename} 失败\n";
Tools::log_to_write_txt(['error'=>"写入文件失败: {$real_path} "]);
return Tools::set_fail('生成音频失败');
}
} else {
//echo "请求失败\n";
Tools::log_to_write_txt(['error'=>"请求失败: {$url} "]);
return Tools::set_fail('生成音频失败');
}
}
/**
* desc创建目录
* authorwh
* @param string $audio_file_name 文件名不能有"空格"等特殊符号
*/
private function createMp3Dir($audio_file_name='')
{
$time = $audio_file_name?:(date('YmdHis'));
$root_path = Tools::get_root_path();
$rel = "audio/{$time}.mp3";
$real_path = $root_path . "public/" . $rel;
$dir = dirname($real_path);
// 检查并创建目录
if (!file_exists($dir)) {
if (!mkdir($dir, 0777, true)) {
//echo "目录 {$dir} 创建成功\n";
//} else {
//echo "目录 {$dir} 创建失败\n";
Tools::log_to_write_txt(['error'=>"目录创建失败: {$dir} "]);
return [];
}
}
return [$real_path, $rel];
}
protected function curlPost($url, $data, $headers, $verifySSL = true)
{
$jsonData = json_encode($data);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if (!$verifySSL) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
}
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
return false;
}
curl_close($ch);
return $response;
}
}

View File

@@ -21,12 +21,12 @@ class Qrcode
{
public $size = 2;
/**
* 创建普通二维码
* 生成带logo的二维码
* authorwh
* doc: https://packagist.org/packages/doing/phpqrcode
* @param string $str 二维码的内容
* @param string $qr_file_name 用户username作为图片名称
* @param string $logo 真实物理路径
* @param string $logo 真实物理路径 必须
* @throws \Exception
*/
function createQrcode(string $str,string $qr_file_name, string $logo=''){
@@ -52,4 +52,32 @@ class Qrcode
return $outfile;
}
/**
* desc生成不带logo的二维码
*
* authorwh
* @param string $content 二维码的内容
* @param string $qr_file_name 二维码图片文件名称(一般为用户唯一id)
* @return string
*/
function generateQrcode($content,$qr_file_name='')
{
if(empty($qr_file_name)){
$qr_file_name = 'qrcode_'.time().rand(1000,9999);
}
$out_path = 'uploads/qr_images/';
if(!file_exists($out_path)){
mkdir($out_path,0777,true);
}
$qrname = $qr_file_name.'.png';
//二维码导出的储存地址
$outfile = $out_path.$qrname;
//二维码的大小
$size = $this->size;
//调用方法成功后,会在相应文件夹下生成二维码文件
\PHPQRCode\QRcode::png($content, $outfile, $size);
return $outfile;
}
}

View File

@@ -224,6 +224,7 @@ EOF;
$request->spbill_create_ip = request()->ip(); // 客户端ip
$request->notify_url = $notify_url; // 异步通知地址
$request->openid = $wx_user_info['openid']; // 必须设置openid
$request->profit_sharing = empty($order_info['profit_sharing'])?'N':$order_info['profit_sharing'];//是否分账N,Y
// 调用接口
$result = $pay->execute($request);
//此调试代码禁止删除
@@ -243,7 +244,7 @@ EOF;
/**
* desc [推荐]微信退款,单位“分”
* desc [推荐]微信退款,传入的金额保持“元”为单位,实际是以“分”的格式提交给微信支付
*
* 依赖yurunsoft/pay-sdk
*
@@ -278,10 +279,15 @@ EOF;
$request->total_fee = $order_info['real_amount'] * 100; // 订单总金额,单位为:分
$request->refund_fee = $order_info['real_amount'] * 100; // 退款金额,单位为:分
// 调用退款接口
Tools::log_to_write_txt(['调用退款接口入参orderid='.$order_info['orderid'],$request]);
$result = $pay->execute($request);
Tools::log_to_write_txt(['调用退款接口,出参:',$result]);
try {
// 调用退款接口
Tools::log_to_write_txt(['调用退款接口入参orderid='.$order_info['orderid'],$request]);
$result = $pay->execute($request);
Tools::log_to_write_txt(['调用退款接口,出参:',$result]);
}catch (\Exception $e){
Tools::error_txt_log($e);
return Tools::set_fail('[err]'.$e->getMessage());
}
// 调试代码
//var_dump('refund result:', $result);