| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- <?php
- namespace addons\JoinPay\common\logic\util;
- use common\helpers\FileHelper;
- use Yii;
- use Exception;
- use addons\JoinPay\common\logic\exceptions\SDKException;
- use addons\JoinPay\common\logic\entity\Request;
- use addons\JoinPay\common\logic\entity\SecretKey;
- use addons\JoinPay\common\logic\entity\Response;
- /**
- * 汇聚扫码支付
- * Class RequestUtil
- * @package addons\JoinPay\common\logic\util
- */
- class RequestUtil
- {
- /**
- * POST请求
- * @param $url
- * @param $params
- * @param bool $contentType
- * @return bool|mixed|string
- */
- public static function http_post($url, $params,$contentType=false)
- {
- if (function_exists('curl_init')) {
- // curl方式
- $oCurl = curl_init();
- if (stripos($url, 'https://') !== FALSE) {
- curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
- curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
- }
- $string = $params;
- if (is_array($params)) {
- $aPOST = array();
- foreach ($params as $key => $val) {
- $aPOST[] = $key . '=' . urlencode($val);
- }
- $string = join('&', $aPOST);
- }
- curl_setopt($oCurl, CURLOPT_URL, $url);
- curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($oCurl, CURLOPT_POST, TRUE);
- //$contentType json处理
- if($contentType){
- $headers = array(
- "Content-type: application/json;charset='utf-8'",
- );
- curl_setopt($oCurl, CURLOPT_HTTPHEADER, $headers);
- curl_setopt($oCurl, CURLOPT_POSTFIELDS, json_encode($params));
- }else{
- curl_setopt($oCurl, CURLOPT_POSTFIELDS, $string);
- }
- $response = curl_exec($oCurl);
- curl_close($oCurl);
- return $response;
- } elseif (function_exists('stream_context_create')) {
- // php5.3以上
- $opts = array(
- 'http' => array(
- 'method' => 'POST',
- 'header' => 'Content-type: application/x-www-form-urlencoded',
- 'content' => http_build_query($params),
- )
- );
- $_opts = stream_context_get_params(stream_context_get_default());
- $context = stream_context_create(array_merge_recursive($_opts['options'], $opts));
- return file_get_contents($url, false, $context);
- } else {
- return false;
- }
- }
- /**
- * 生成签名
- * @param $params
- * @param $key
- * @param string $encryptType
- * @return string
- */
- public static function hmacRequest($params, $key, $encryptType = "1")
- {
- if ("1" == $encryptType) {
- $str = implode("", $params) . $key;
- return md5($str);
- } else {
- $private_key = openssl_pkey_get_private($key);
- $params = implode("", $params);
- openssl_sign($params, $sign, $private_key, OPENSSL_ALGO_MD5);
- openssl_free_key($private_key);
- $sign = base64_encode($sign);
- return $sign;
- }
- }
- /**
- * 发起交易请求
- * 说明:
- * 1、此方法不会对商户私钥做任何处理,理论上不会造成私钥泄漏,如果商户觉得把私钥传递到此方法不安全,可以在调用本方法前
- * 自行调用SignUtil的相关方法为请求参数生成签名,自行调用RSAUtil的相关方法对sec_key进行加解密。
- * 2、发起请求时,如果SecretKey.reqSignKey不为空,当前方法会自动为请求参数生成签名、得到系统响应之后也会自动对响应
- * 数据进行验签,签名或验签失败会抛出 SDKException 异常
- * 3、发送请求时,如果Request中的sec_key和SecretKey.secKeyEncryptKey都不为空,会自动给sec_key加密
- * 4、得到响应时,如果Response中的sec_key和SecretKey.secKeyDecryptKey都不为空,会自动给sec_key解密
- *
- * @param string $url
- * @param Request $request
- * @param SecretKey $secretKey
- * @return Response
- * @throws SDKException
- * @throws \ReflectionException
- */
- public static function doRequest(string $url, Request $request, SecretKey $secretKey){
- //1.参数校验
- self::requestParamValid($request, $secretKey);
- if(! is_string($request->getData())){
- $request->setData(json_encode($request->getData(), JSON_UNESCAPED_UNICODE));
- }
- //2.添加签名
- if($secretKey->getReqSignKey()){
- $signStr = SignUtil::getSortedString($request, false);
- Yii::error('$signStr =' . $signStr);
- $signStr = SignUtil::sign($signStr, $request->getSignType(), $secretKey->getReqSignKey());
- Yii::error('$signStr =' . $signStr);
- $request->setSign($signStr);
- }else if(! $request->getSign()){
- throw new SDKException(SDKException::BIZ_ERROR, "请对请求参数添加签名!");
- }
- //3.如果存在sec_key,则对其进行rsa加密
- if($request->getSecKey() && $secretKey->getSecKeyEncryptKey()){
- $request->setSecKey(RSAUtil::encrypt($request->getSecKey(), $secretKey->getSecKeyEncryptKey()));
- }
- \Yii::error('$request ='.json_encode($request));
- //4.发起http请求
- $respJson = HttpUtil::postJsonSync($url, json_encode($request, JSON_UNESCAPED_UNICODE));
- if(! $respJson){
- throw new SDKException(SDKException::BIZ_ERROR, "请求完成,但响应信息为空");
- }
- \Yii::error('resp ='.json_encode($respJson));
- //5.响应结果转换
- $response = new Response();
- try{
- ObjectUtil::fillProperties($response, $respJson);
- }catch (Exception $e){
- throw new SDKException(SDKException::BIZ_ERROR, "请求完成,但响应信息转换失败: " . $e->getMessage() . ",respJson = " . $respJson);
- }
- $isOk = false;
- try{
- $signStr = SignUtil::getSortedString($response, false);
- $isOk = SignUtil::verify($signStr, $response->getSign(), $response->getSignType(), $secretKey->getRespVerifyKey());
- }catch (Exception $e){
- throw new SDKException(SDKException::BIZ_ERROR, "请求完成,但响应信息验签异常: " . $e->getMessage() . ",respJson = " . $respJson);
- }
- if($isOk !== true){
- throw new SDKException(SDKException::BIZ_ERROR, "响应信息验签不通过! respJson = " . $respJson);
- }
- if($response->getSecKey() && $secretKey->getSecKeyDecryptKey()){
- $secKey = RSAUtil::decrypt($response->getSecKey(), $secretKey->getSecKeyDecryptKey());
- $response->setSecKey($secKey);
- }
- return $response;
- }
- /**
- * 简单参数校验
- * @param Request $request
- * @param SecretKey $secretKey
- * @throws Exception
- */
- private static function requestParamValid(Request $request, SecretKey $secretKey){
- if(! $request){
- throw new SDKException(SDKException::PARAM_ERROR, "request不能为空");
- }else if(! $request->getMethod()){
- throw new SDKException(SDKException::PARAM_ERROR, "Request.method不能为空");
- }else if(! $request->getVersion()){
- throw new SDKException(SDKException::PARAM_ERROR, "Request.version不能为空");
- }else if(! $request->getData()){
- throw new SDKException(SDKException::PARAM_ERROR, "Request.data不能为空");
- }else if(! $request->getSignType()){
- throw new SDKException(SDKException::PARAM_ERROR, "Request.sign_type不能为空");
- }else if(! $request->getMchNo()){
- throw new SDKException(SDKException::PARAM_ERROR, "Request.mch_no不能为空");
- }
- if(! $secretKey){
- throw new SDKException(SDKException::PARAM_ERROR, "secretKey不能为空");
- }else if(! $secretKey->getRespVerifyKey()){
- throw new SDKException(SDKException::PARAM_ERROR, "SecretKey.respVerifyKey不能为空");
- }
- }
- }
|