* @version : HUOSDK 8.0 */ namespace huolib\pay\driver; use huolib\constant\PaywayConst; use huolib\pay\Driver; use huolib\status\OrderStatus; use think\Exception; use think\Loader; use think\Log; class Alipay extends Driver { private $config = [ 'partner' => '', 'seller_email' => '', 'key' => '', 'sign_type' => '', 'input_charset' => 'utf-8', // 编码 (固定值不用改) 'transport' => 'http', // 协议 (固定值不用改) 'cacert' => '', 'notify_url' => '', 'return_url' => '', 'show_url' => '', 'private_key_path' => '', 'public_key_path' => '', ]; /** * 构造函数 */ public function __construct() { if (file_exists(GLOBAL_CONF_PATH."extra/pay/alipay/config.php")) { $_config = include GLOBAL_CONF_PATH."extra/pay/alipay/config.php"; } else { $_config = array(); } $this->config = array_merge($this->config, $_config); $this->config['sign_type'] = strtoupper(trim('RSA')); $this->config['cacert'] = GLOBAL_CONF_PATH.'extra/pay/alipay/cacert.pem'; $this->config['private_key_path'] = GLOBAL_CONF_PATH.'extra/pay/alipay/key/rsa_private_key.pem'; $this->config['public_key_path'] = GLOBAL_CONF_PATH.'extra/pay/alipay/key/alipay_public_key.pem'; $this->notify_url = get_val($this->config, 'notify_url', ''); } /** * 设置配置 * * @param array $config */ public function setConf($config = []) { if (!empty($config)) { $this->config['partner'] = $config['partner']; $this->config['seller_email'] = $config['seller_email']; $this->config['key'] = $config['key']; $this->config['sign_type'] = $config['sign_type']; $this->config['private_key_path'] = $config['private_key_path']; $this->config['public_key_path'] = $config['public_key_path']; } } /** * 移动APP支付函数 * * @param array $config * * @return bool| array * @throws Exception */ public function clientPay($config = []) { $this->setConf($config); $_config = $this->config; if (empty($_config['key'])) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&config=".$_config."&code=".OrderStatus::ALIPAY_CONFIG_ERROR ."&msg=".OrderStatus::getMsg(OrderStatus::ALIPAY_CONFIG_ERROR), LOG::ERROR ); throw new Exception( OrderStatus::getMsg(OrderStatus::ALIPAY_CONFIG_ERROR), OrderStatus::ALIPAY_CONFIG_ERROR ); } $_config['notify_url'] = $this->notify_url; $_config['return_url'] = $this->return_url; $_config['show_url'] = $this->show_url; $_data = array( "service" => "mobile.securitypay.pay", "partner" => trim($this->config['partner']), "_input_charset" => trim(strtolower($this->config['input_charset'])), "sign_type" => strtoupper(trim($this->config['sign_type'])), "notify_url" => $this->notify_url, "out_trade_no" => $this->order_id, "subject" => $this->product_name, "body" => $this->product_id, "payment_type" => "1", "seller_id" => trim($this->config['seller_email']), "total_fee" => $this->real_amount, "it_b_pay" => "30m" ); Loader::import('pay.alipay.AlipaySubmit', '', '.class.php'); // 建立请求,请求成功之后,会通知服务器的alipay_notify方法,客户端会通知$return_url配置的方法 $_alipay_submit = new \AlipaySubmit($this->config); $_token = $_alipay_submit->buildClientRequestParaToString($_data); return $this->clientAjax(PaywayConst::PAYWAY_ALIPAY, $_token, 1, 2, 1); } /** * wap端下单 * * @param array $config * * @return bool * @throws Exception */ public function mobilePay($config = []) { $this->setConf($config); $_config = $this->config; if (empty($_config['key'])) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&config=".$_config."&code=".OrderStatus::ALIPAY_CONFIG_ERROR ."&msg=".OrderStatus::getMsg(OrderStatus::ALIPAY_CONFIG_ERROR), LOG::ERROR ); throw new Exception( OrderStatus::getMsg(OrderStatus::ALIPAY_CONFIG_ERROR), OrderStatus::ALIPAY_CONFIG_ERROR ); } $_config['notify_url'] = $this->notify_url; $_config['return_url'] = $this->return_url; $_config['show_url'] = $this->show_url; $_data = array( "service" => "alipay.wap.create.direct.pay.by.user", "partner" => trim($_config['partner']), "_input_charset" => trim(strtolower($_config['input_charset'])), "sign_type" => strtoupper(trim($_config['sign_type'])), "notify_url" => $this->notify_url, "return_url" => $this->return_url, "show_url" => $this->show_url, "out_trade_no" => $this->order_id, "subject" => $this->product_name, "body" => $this->product_id, "payment_type" => "1", "seller_id" => trim($this->config['seller_email']), "total_fee" => $this->real_amount, "app_pay" => 'Y', "it_b_pay" => "30m" ); Loader::import('pay.alipay.AlipaySubmit', '', '.class.php'); // 建立请求,请求成功之后,会通知服务器的alipay_notify方法,客户端会通知$return_url配置的方法 $_alipay_submit = new \AlipaySubmit($this->config); $_html_text = $_alipay_submit->buildRequestForm($_data, "get", "跳转中"); header("Content-type:text/html;charset=utf-8"); /* Modified by ouzhongfu BEGIN 2019/2/16 ISSUES:8103 支付宝调起方式修改 */ $_pay_type = PaywayConst::PAYWAY_ALIPAYH5; $_btoken = ''; if ($this->getUseProtocol()) { $_btoken = $_html_text; $_html = $_alipay_submit->alipay_gateway_new.$_alipay_submit->buildRequestParaToString($_data); $_html_result = $this->getAlipayUrl($_html); $_device_type = request()->getDeviceOsType(); if ('ios' == $_device_type) { $_pay_type = PaywayConst::PAYWAY_ALIPAYXY; $_html_text = $_html_result['deeplink_ios']; } else { $_pay_type = PaywayConst::PAYWAY_ALIPAYXY; $_html_text = $_html_result['deeplink_android']; } } /* END 2019/2/16 ISSUES:8103 */ return $this->clientAjax($_pay_type, $_html_text, 1, 1, 1, $_btoken); } /** * PC端下单 * * @param array $config * * @return bool * @throws Exception */ public function pcPay($config = []) { $this->setConf($config); $_config = $this->config; if (empty($_config['key'])) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&config=".$_config."&code=".OrderStatus::ALIPAY_CONFIG_ERROR ."&msg=".OrderStatus::getMsg(OrderStatus::ALIPAY_CONFIG_ERROR), LOG::ERROR ); throw new Exception( OrderStatus::getMsg(OrderStatus::ALIPAY_CONFIG_ERROR), OrderStatus::ALIPAY_CONFIG_ERROR ); } $_config['notify_url'] = $this->notify_url; $_config['return_url'] = $this->return_url; $_config['show_url'] = $this->show_url; $_data = array( "service" => "create_direct_pay_by_user", "partner" => trim($_config['partner']), "seller_id" => trim($_config['partner']), "payment_type" => "1", "notify_url" => $this->notify_url, "return_url" => $this->return_url, "out_trade_no" => $this->order_id, "subject" => $this->product_name, "total_fee" => $this->real_amount, "show_url" => $this->show_url, "body" => $this->product_id, "it_b_pay" => "15d", "_input_charset" => trim(strtolower($_config['input_charset'])) ); Loader::import('pay.alipay.AlipaySubmit', '', '.class.php'); //建立请求 $_alipay_submit = new \AlipaySubmit($_config); $_html_text = $_alipay_submit->buildRequestForm($_data, "get", "跳转中"); return $this->clientAjax(PaywayConst::PAYWAY_ALIPAYQR, $_html_text, 1, 1, 1); } /** * 异步回调函数 * * @param array $config */ public function notifyUrl($config = []) { $this->setConf($config); // 引入支付宝 Loader::import('pay.alipay.AlipayNotify', '', '.class.php'); $_ali_notify = new \AlipayNotify($this->config); // 验证支付数据 $_verify_result = $_ali_notify->verifyNotify(); if ($_verify_result) { /* 平台订单号 */ $_out_trade_no = $_POST['out_trade_no']; /* 支付宝交易号 */ $_trade_no = $_POST['trade_no']; /* 交易金额 */ $_amount = $_POST['total_fee']; /* 该笔订单的备注、描述、明细等。对应请求时的body参数,原样通知回来。 */ $_product_id = $_POST['body']; // 交易状态 $trade_status = $_POST['trade_status']; if ($trade_status == 'TRADE_FINISHED') { } else if ($trade_status == 'TRADE_SUCCESS') { $_class = $this->order_class; $_func = $this->func; try { if (class_exists($_class)) { $_order = new $_class(); $_order->$_func($_product_id, $_out_trade_no, $_trade_no, $_amount, 'alipay'); } else { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&order_class=".$_class ."&func=".$_func, LOG::ERROR ); } } catch (Exception $_e) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&order_class=".$_class ."&func=".$_func."&err=".$_e->getMessage()."&errCode=".$_e->getCode(), LOG::ERROR ); } } echo "success"; // 下面写验证通过的逻辑 比如说更改订单状态等等 $_POST['out_trade_no'] 为订单号; } else { echo "fail"; } } /** * 返回接收页面 * * @param array $config * * @return bool */ public function returnUrl($config = []) { $this->setConf($config); //计算得出通知验证结果 // 引入支付宝 Loader::import('pay.alipay.AlipayNotify', '', '.class.php'); $alipayNotify = new \AlipayNotify($this->config); $verify_result = $alipayNotify->verifyReturn(); if ($verify_result) { //验证成功 $_status = 2; } else { $_status = 3; } return $this->clientAjax(PaywayConst::PAYWAY_ALIPAY, $_status, $_status, 1, 1); } /** * 查询订单 * * @access public * * @param string $order_id 商户系统内部订单号 * @param string $transaction_id 第三方支付的订单号 * @param null $ext 扩展信息 * * @return bool|string */ public function orderQuery($order_id, $transaction_id, $ext = null) { return true; } public function getAlipayUrl($html) { $_headers = array('CLIENT-IP' => $this->ip, 'X-FORWARDED-FOR' => $this->ip); $_header_arr = array(); foreach ($_headers as $_n => $_v) { $_header_arr[] = $_n.':'.$_v; } $_options = array( CURLOPT_REFERER => SDKSITE, CURLOPT_USERAGENT => 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1', CURLOPT_FOLLOWLOCATION => 1, CURLOPT_HTTPHEADER => $_header_arr ); $_html = $this->singleGrabGetdata($html, $_options); $_p = '/{\"requestType.*?\"}/'; preg_match($_p, $_html, $_match); $_result['deeplink_ios'] = ''; $_result['deeplink_android'] = ''; if (isset($_match[0])) { $_args = json_decode($_match[0], true); $_result['deeplink_ios'] = 'alipay://alipayclient/?'.urlencode(json_encode($_args)); // $_result['deeplink_android'] = 'alipay://alipayclient/?'.urlencode($_args['dataString']); $_result['deeplink_android'] = 'alipays://platformapi/startApp?appId=20000125&orderSuffix='.urlencode( $_args['dataString'] ); } return $_result; } /**获取支付宝吊起地址 * * @param $url * @param null $opts * * @return bool|mixed */ public function singleGrabGetdata($url, $opts = null) { if (empty($url)) { return false; } $ch = curl_init(); $options = array( CURLOPT_URL => $url, CURLOPT_USERAGENT => "spider", CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, ); if (!is_null($opts)) { foreach ($opts as $k => $v) { $options[$k] = $v; } unset($k, $v); } curl_setopt_array($ch, $options); $tmpResult = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($httpCode == 200) { curl_close($ch); return $tmpResult; } return false; } }