*/ namespace weChat\pay; use think\Exception; trait BasicsAction { /** * 初始加载 */ private function init() { $this->getIp(); // 获取ip $this->random(); // 生成随机数 $this->outTradeNo(); // 生成订单号 $this->time_start = date('YmdHis', $_SERVER['REQUEST_TIME']); // 开始时间 $this->time_expire = date('YmdHis', $_SERVER['REQUEST_TIME'] + 3600);// 结束时间 $this->sign_type = 'MD5'; // 签名加密方式 } /** * 获取appid等基础重要参数 * @param string $param * @return mixed */ private function getParam(string $param) { $config_param = [ self::JS_API => '\\weChat\\common\\Config::xPay', self::H5 => '\\weChat\\common\\Config::xPay', self::APP => '\\weChat\\common\\Config::appPay', self::NATIVE => '\\weChat\\common\\Config::sPay', ]; return call_user_func($config_param[$this->trade_type], $param); } /** * 获取并设置客户端IP */ private function getIp() { $unknown = 'unknown'; if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], $unknown)) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], $unknown)) { $ip = $_SERVER['REMOTE_ADDR']; } /* 处理多层代理的情况 或者使用正则方式:$ip = preg_match("/[\d\.]{7,15}/", $ip, $matches) ? $matches[0] : $unknown; */ if (false !== strpos($ip, ',')) $ip = explode(',', $ip)[0]; $this->spbill_create_ip = $ip; } /** * 生成随机字符串 * @return string */ private function random() { $array = array_merge(range('A', 'Z'), range('a', 'z'), range(0, 9)); $random = mt_rand(24, 31); $length = count($array); $array[] = substr(time(), -1); $string = ''; for ($i = 0; $i <= $random; ++$i) { $string .= $array[mt_rand(0, $length)]; } $this->nonce_str = $string; return $string; } /** * 生成签名 * @param array $signArray * @return string */ private function sign(array $signArray = []) { if (empty($signArray)) { foreach ($this as $key => $value) { if ($key != 'key' && $value) $signArray[$key] = $value; } } ksort($signArray); $signString = ''; foreach ($signArray as $key => $value) { $signString .= $key . '=' . $value . '&'; } $signString .= 'key=' . $this->key; $sign_type = $this->sign_type ?? 'md5'; $this->sign = strtoupper($sign_type($signString)); return $this->sign; } /** * 生成订单号 */ private function outTradeNo() { $this->out_trade_no = date('Ymd') . $_SERVER['REQUEST_TIME'] . mt_rand(100000, 999999); } /** * 生成xml数据 * @param array $data * @return string */ private function xml($data = []) { $data or $this->sign(); // 生成签名 $xml = '' . PHP_EOL; foreach (($data ?: $this) as $k => $v) { if ($v && $k != 'key') { $xml .= "<{$k}>{$v}" . PHP_EOL; } } $xml .= ''; return $xml; } /** * 获取内部属性 * @param $attr * @return string */ public function getAttr($attr = '') { return $this->$attr ?? ''; } /** * 设置appid,用于多个小程序一个后端 * @param $appId * @return $this */ public function setAppId($appId) { if ($appId) { $this->appid = $appId; } return $this; } /** * 设置商户号和对应的秘钥 * @param $mch string 商户号 * @param $key string 秘钥 * @return $this */ public function setMchAndKey($mch, $key) { if (!empty($mch) && !empty($key)) { $this->mch_id = $mch; $this->key = $key; } return $this; } /** * 设置场景值(H5支付时的) * @param $url string 网站地址 * @param $name string 网站名字 */ public function setSceneInfo($url, $name) { $scene_info = [ 'store_info' => [ 'type' => 'Wap', 'wap_url' => $url, 'wap_name' => $name ] ]; $this->scene_info = json_encode($scene_info, JSON_UNESCAPED_UNICODE); } /** * 发起post请求 * @param string $url 路径 * @param mixed $data 数据 * @param array|null $cert 证书 * @return mixed * @throws Exception */ private static function postRequest($url, $data, array $cert = null) { $headerArray = array("Content-type:application/xml;charset='utf-8'"); $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); curl_setopt($curl, CURLOPT_HTTPHEADER, $headerArray); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); if ($cert !== null){ curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'pem'); curl_setopt($curl, CURLOPT_SSLCERT, $cert['cert']); curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'pem'); curl_setopt($curl, CURLOPT_SSLKEY, $cert['key']); } $output = curl_exec($curl); if (curl_errno($curl)) { throw new Exception(curl_error($curl)); } curl_close($curl); return $output; } }