PHP功能实现之微信提现(企业付款)

官方文档:企业付款

<?php
namespace App\Helpers\Unit\Behaviour;
use App\Helpers\Traits\Logs;
use App\Models\PayTakeoutLogModels AS mPayTakeoutLog;

/**
 * 组件 - 微信提现
 *
 * @version  1.0.0
 * @author   Yunuo <ciwdream@gmail.com>
 * @link https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
 */
class WeChaTtakeoutUnit
{
    use Logs;

    /**
     * 商户账号appid
     *
     * @var string $_appid
     */
    private $_appid     = '';

    /**
     * ApiKey密码
     *
     * @var string $_apiKey
     */
    private $_apiKey = '';

    /**
     * 商户号
     *
     * @var int $_mchId
     */
    private $_mchId     = '';

    /**
     * 授权用户openid
     *
     * @var int $_openid
     */
    private $_openid    = '';


    private $_param  = [];
    private $_models = null;
    private $_orderInfo = [];


    /**
     * 实例化
     *
     * @param string  $trade_no 提现订单号
     *
     * @return void
     */
    public function __construct($trade_no)
    {
        $this->_models = new mPayTakeoutLog();
        $this->_isOrderExist($trade_no);
        $this->_param['mch_appid'] = $this->_appid;
        $this->_param['mchid']     = $this->_mchId;
        $this->_param['nonce_str'] = $this->_nonceStr();
        $this->_param['partner_trade_no'] = $trade_no;
        $this->_param['check_name'] = 'NO_CHECK';
    }

    /**
     * 发起提现
     *
     * @param string  $clientIP 客户端IP
     * @param integer $money    提现金额(单位:分)
     * @param string  $desc     提现备注信息
     *
     * @return bool
     */
    public function transfers($clientIP,$money,$desc=null)
    {
        if(empty($this->_orderInfo))return false;
        $_allow = false;

        $this->_param['openid'] = $this->_openid;
        $this->_param['amount'] = $money; //付款金额,单位为分
        $this->_param['desc']   = empty($desc)?'':$desc;
        $this->_param['spbill_create_ip'] = $clientIP; // 获取服务器的ip
        $this->_param['sign'] = $this->_createSign($this->_param);
        if( $_return = $this->_curlPostSsl($this->_param) ){
            if ($_return['return_code'] == 'SUCCESS' && $_return['result_code'] == 'SUCCESS') {
                $_orderInfo = $this->_models
                    ->where('trade_no',$this->_param['partner_trade_no'])
                    ->update(['pay_state'=>1,'pay_time'=>date('Y-m-d H:i:s')]);
                if( $_orderInfo ){
                    $this->_isOrderExist($this->_param['partner_trade_no']); // 更新类属性中的订单信息
                    self::logRecord('info','[微信提现 -> transfers]订单处理成功'.var_export($this->_param,true));
                    $_allow = true;
                }else{
                    self::logRecord('error','[微信提现 -> transfers]订单处理失败'.var_export($this->_param,true));
                }
            }else{
                self::logRecord('error','[微信提现 -> transfers]请求处理失败'.var_export($_return,true));
            }
        }else{
            self::logRecord('error','[微信提现 -> transfers]请求处理失败'.var_export($_return,true));
        }
        return $_allow;
    }

    /**
     * 设置Openid
     *
     * @param string $openid  用户openid
     *
     * @return void
     */
    public function setOpenid($openid) : void
    {
        $this->_openid = $openid;
    }

    /**
     * 生成随机字符串
     *
     * @return string 随机字符串,不长于32位
     */
    private function _nonceStr() : string
    {
        return md5(uniqid(microtime(true),true));
    }

    /**
     * 生成校验Sign
     *
     * @param array $param 待校验数据
     *
     * @return string 签名
     */
    private function _createSign($param) : string
    {
        $param = array_filter($param);
        ksort($param);
        $string="";
        foreach ($param as $k => $v) {

            if($k != "sign" && $v != "" && !is_array($v)){
                $string .= $k . "=" . $v . "&";
            }
        }
        $string = $string . "key=".$this->_apiKey;
        $string = md5($string);
        $result = strtoupper($string);
        return $result;
    }

    /**
     * CURL微信
     *
     * @param array $param 待发送数据
     *
     * @return string|bool
     */
    private function _curlPostSsl($param)
    {
        header("Content-Type: text/html; charset=utf-8");
        $_isdir   = resource_path('cert').DIRECTORY_SEPARATOR; // 证书位置
        $_apiUrl  = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
        $_aHeader = [];

        $_sendData = $this->_toXml($param);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_URL, $_apiUrl);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);// 终止从服务端进行验证
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');//证书类型
        curl_setopt($ch, CURLOPT_SSLCERT, $_isdir . 'apiclient_cert.pem');//证书位置
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');//CURLOPT_SSLKEY中规定的私钥的加密类型
        curl_setopt($ch, CURLOPT_SSLKEY, $_isdir . 'apiclient_key.pem');//证书位置
        if (count($_aHeader) >= 1) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $_aHeader);//设置头部
        }
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $_sendData);

        $data = curl_exec($ch);
        if ($data) {
            curl_close($ch);
            if( !is_string($data) ){
                self::logRecord('error','[微信提现 -> _curlPostSsl]curl返回数据::'.var_export($data,true));
                return false;
            }
            return $this->_fromXml($data);
        } else {
            $error = curl_errno($ch);
            self::logRecord('error','[微信提现 -> _curlPostSsl]curl出错,错误码::'.$error);
            curl_close($ch);
            return false;
        }
    }

    /**
     * 输出xml字符
     *
     * @param array $param 待转化数组
     *
     * @return string Xml
     **/
    private function _toXml($param) : string
    {
        $xml = "<xml>";
        foreach ($param as $key=>$val)
        {
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }

    /**
     * 将xml转为array
     *
     * @param string $xml 待转化XML数据
     *
     * @return array
     */
    private function _fromXml($xml) : array
    {
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }

    /**
     * 判断订单是否存在
     *
     * @param string $trade_no 待处理订单号
     *
     * @return bool
     */
    private function _isOrderExist($trade_no) : bool
    {
        $_orderInfo = $this->_models
            ->where('trade_no',$trade_no)
            ->first();
        if( $_orderInfo ){
            $this->_orderInfo = $_orderInfo->toArray();
            if( 1 === $this->_orderInfo['pay_state'] ){
                $this->_orderInfo = [];
                return false;
            }
            return true;
        }else{
            $this->_orderInfo = [];
            return false;
        }
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据提供的引用内容,我无法找到关于禅道实现企业微信扫码登录功能的具体信息。但是,我可以为您提供一般的步骤和示例代码来实现这个功能。 要实现企业微信扫码登录功能,您可以按照以下步骤进行操作: 1. 在企业微信开发者平台上创建一个应用,并获取到应用的CorpID和Secret。 2. 在禅道系统中创建一个新的登录方式,选择企业微信扫码登录。 3. 在禅道系统中配置企业微信扫码登录的相关参数,包括CorpID、Secret等。 4. 在禅道系统中生成一个用于回调的URL,用于接收企业微信返回的授权码。 5. 在禅道系统中生成一个用于生成二维码的URL,用于展示给用户扫码登录。 6. 在禅道系统中编写处理回调的代码,用于获取企业微信返回的授权码,并根据授权码获取用户的详细信息。 7. 在禅道系统中根据用户的详细信息进行登录或注册操作。 以下是一个简单的PHP示例代码,用于生成企业微信扫码登录的二维码: ```php <?php $corpId = 'your_corp_id'; $redirectUri = 'your_callback_url'; $authUrl = 'https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=' . $corpId . '&agentid=AGENTID&redirect_uri=' . urlencode($redirectUri) . '&state=STATE'; echo '<img src="' . $authUrl . '" alt="企业微信扫码登录">'; ?> ``` 请注意,上述示例代码中的`your_corp_id`和`your_callback_url`需要替换为您自己的CorpID和回调URL。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陀螺蚁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值