From c5259358c70ac6ea0c15bcb69c05cd04601128d4 Mon Sep 17 00:00:00 2001 From: JING Date: Thu, 4 Jun 2026 16:37:47 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E4=B8=80=E7=BA=A7=E5=B8=82=E5=9C=BA?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Constant.php | 159 +++++++++++++ src/HFPayClient.php | 12 + src/factory/impl/OneLevelFactory.php | 212 +++++++++++++++++ .../object/onelevel/CompanyRequest.php | 214 ++++++++++++++++++ .../object/onelevel/CompanyResponse.php | 14 ++ .../object/onelevel/PeddlarRequest.php | 157 +++++++++++++ .../object/onelevel/PeddlarResponse.php | 14 ++ .../object/onelevel/PersonalRequest.php | 91 ++++++++ .../object/onelevel/PersonalResponse.php | 13 ++ src/factory/object/onelevel/UploadRequest.php | 73 ++++++ .../object/onelevel/UploadResponse.php | 13 ++ 11 files changed, 972 insertions(+) create mode 100644 src/factory/impl/OneLevelFactory.php create mode 100644 src/factory/object/onelevel/CompanyRequest.php create mode 100644 src/factory/object/onelevel/CompanyResponse.php create mode 100644 src/factory/object/onelevel/PeddlarRequest.php create mode 100644 src/factory/object/onelevel/PeddlarResponse.php create mode 100644 src/factory/object/onelevel/PersonalRequest.php create mode 100644 src/factory/object/onelevel/PersonalResponse.php create mode 100644 src/factory/object/onelevel/UploadRequest.php create mode 100644 src/factory/object/onelevel/UploadResponse.php diff --git a/src/Constant.php b/src/Constant.php index 23965f0..738b390 100644 --- a/src/Constant.php +++ b/src/Constant.php @@ -89,4 +89,163 @@ class Constant const RISK_DIV_TYPE_MASTER = 1; const RISK_DIV_TYPE_FEE = 2; const RISK_DIV_TYPE_OTHER = 3; + + /** + * 一级市场->文件上传->业务类型 trans_type 3:企业开户4:个体户开户 7:个人开户 + * */ + + const ONE_UP_TRANS_TYPE_COMPANY = 3; + const ONE_UP_TRANS_TYPE_PEDDLER = 4; + const ONE_UP_TRANS_TYPE_PERSONAL = 7; + + /** + * 一级市场->文件上传->附件类型 attach_type + * + 1:营业执照注册号 + 2:组织结构代码证 + 3:税务登记证号 + 4:法人证件 + 5:开户银行许可证 + 6:统一社会信用代码 + 7:快捷协议 + 8:代扣协议 + 9:开户电子协议 + 10:法人证件反面 + 11:经营照片 + 12:经营照片(地址照片) + 13:经营照片(门头照片) + 14:结算卡正面 + 15:结算卡反面 + 16:经办人证件 + 21:个人身份证正面 + 22:个人身份证反面 + 23:用户平台合作协议 + 99.其他 + * + * */ + const ONE_UP_ATTACH_TYPE_1 = 1; + const ONE_UP_ATTACH_TYPE_2 = 2; + const ONE_UP_ATTACH_TYPE_3 = 3; + const ONE_UP_ATTACH_TYPE_4 = 4; + const ONE_UP_ATTACH_TYPE_5 = 5; + const ONE_UP_ATTACH_TYPE_6 = 6; + const ONE_UP_ATTACH_TYPE_7 = 7; + const ONE_UP_ATTACH_TYPE_8 = 8; + const ONE_UP_ATTACH_TYPE_9 = 9; + const ONE_UP_ATTACH_TYPE_10 = 10; + const ONE_UP_ATTACH_TYPE_11 = 11; + const ONE_UP_ATTACH_TYPE_12 = 12; + const ONE_UP_ATTACH_TYPE_13 = 13; + const ONE_UP_ATTACH_TYPE_14 = 14; + const ONE_UP_ATTACH_TYPE_15 = 15; + const ONE_UP_ATTACH_TYPE_16 = 16; + const ONE_UP_ATTACH_TYPE_21 = 21; + const ONE_UP_ATTACH_TYPE_22 = 22; + const ONE_UP_ATTACH_TYPE_23 = 23; + const ONE_UP_ATTACH_TYPE_99 = 99; + + /** + * 一级市场->文件上传->上传类型 handel_type 1:新增 2:更新 + * */ + + const ONE_UP_HANDEL_TYPE_ADD = 1; + const ONE_UP_HANDEL_TYPE_UPDATE = 2; + + + + /** + * 一级市场-> + * 个人用户开户接口(后台版)/ 企业用户开户接口(后台版) + * ->账户用途 acct_usage_type + * one-level-seller:一级市场卖家户 salesr-promoter:分销员户 + * */ + + const ONE_COM_ACCT_USAGE_TYPE_ONE = 'one-level-seller'; + const ONE_COM_ACCT_USAGE_TYPE_SALESR = 'salesr-promoter'; + + /** + * 一级市场->个人用户开户接口(后台版)->个人职业 occupation + * + * 01:国家机关、党群机关、企事业单位负责人 + 02:金融业从业人员 + 03:房地产业从业人员 + 04:商贸从业人员 + 05:自由职业者 + 06:科教文从业人员 + 07:制造业从业人员 + 08:卫生行业从业人员 + 09:IT业从业人员 + 10:农林牧渔劳动者 + 11:生产工作、运输工作和部分体力劳动者 + 12:退休人员 + 13:不便分类的其他劳动者 + * */ + const ONE_PER_OCCUPATION_1 = '01'; + const ONE_PER_OCCUPATION_2 = '02'; + const ONE_PER_OCCUPATION_3 = '03'; + const ONE_PER_OCCUPATION_4 = '04'; + const ONE_PER_OCCUPATION_5 = '05'; + const ONE_PER_OCCUPATION_6 = '06'; + const ONE_PER_OCCUPATION_7 = '07'; + const ONE_PER_OCCUPATION_8 = '08'; + const ONE_PER_OCCUPATION_9 = '09'; + const ONE_PER_OCCUPATION_10 = '10'; + const ONE_PER_OCCUPATION_11 = '11'; + const ONE_PER_OCCUPATION_12 = '12'; + const ONE_PER_OCCUPATION_13 = '13'; + + /** + * 一级市场-> + * 企业用户开户接口(后台版) /个体户开户接口(后台版) + * ->操作类型 operate_type + * A:新增 M:修改 + * */ + const ONE_COM_OPERATE_TYPE_A = 'A'; + const ONE_COM_OPERATE_TYPE_M = 'M'; + + + /** + * 一级市场-> + * 企业用户开户接口(后台版) + * ->企业证照类型 corp_license_type + * 1.普通证照 2.三证合一 + * */ + const ONE_COM_CORP_LIS_TYPE_1 = 1; + const ONE_COM_CORP_LIS_TYPE_2 = 2; + + /** + * 一级市场-> + * 企业用户开户接口(后台版) + * ->法人证件类型 legal_id_card_type /控股股东(实际控制人) controlling_shareholder -> idCardType + * 10:身份证 + 11:护照 + 12:军官证 + 13:士兵证 + 14:回乡证 + 15:户口本 + 16:警官证 + 17:台胞证 + 18:组织机构代码 + 19:营业执照 + 20:税务登记证 + 21:统一社会信用代码证 + 22:其他 + * */ + const ONE_COM_ID_CARD_TYPE_10 = 10; + const ONE_COM_ID_CARD_TYPE_11 = 11; + const ONE_COM_ID_CARD_TYPE_12 = 12; + const ONE_COM_ID_CARD_TYPE_13 = 13; + const ONE_COM_ID_CARD_TYPE_14 = 14; + const ONE_COM_ID_CARD_TYPE_15 = 15; + const ONE_COM_ID_CARD_TYPE_16 = 16; + const ONE_COM_ID_CARD_TYPE_17 = 17; + const ONE_COM_ID_CARD_TYPE_18 = 18; + const ONE_COM_ID_CARD_TYPE_19 = 19; + const ONE_COM_ID_CARD_TYPE_20 = 20; + const ONE_COM_ID_CARD_TYPE_21 = 21; + const ONE_COM_ID_CARD_TYPE_22 = 22; + + + + } \ No newline at end of file diff --git a/src/HFPayClient.php b/src/HFPayClient.php index d323d6c..460c067 100644 --- a/src/HFPayClient.php +++ b/src/HFPayClient.php @@ -11,6 +11,7 @@ use Tansilu\HfPayLib\factory\impl\ManageFactory; use Tansilu\HfPayLib\factory\impl\MarketFactory; use Tansilu\HfPayLib\factory\impl\QueryFactory; use Tansilu\HfPayLib\factory\impl\TradeFactory; +use Tansilu\HfPayLib\factory\impl\OneLevelFactory; use Tansilu\HfPayLib\http\IHttpClient; use Tansilu\HfPayLib\http\impl\HFPayHttpClient; @@ -102,4 +103,15 @@ class HFPayClient { return $this->container->make(TradeFactory::class); } + /** + * 一级市场 + * + * @return OneLevelFactory + * @throws DependencyException + * @throws NotFoundException + */ + public function one(): OneLevelFactory + { + return $this->container->make(OneLevelFactory::class); + } } \ No newline at end of file diff --git a/src/factory/impl/OneLevelFactory.php b/src/factory/impl/OneLevelFactory.php new file mode 100644 index 0000000..816d79b --- /dev/null +++ b/src/factory/impl/OneLevelFactory.php @@ -0,0 +1,212 @@ +toParams(); + + $data = $this->post('/api/alseFile/file01', $request); + + if(!$data->isSuccess()) { + throw new BizException('上传失败', $data->getCode()); + } + return UploadResponse::make($data->getBody()); + } + /** + * 个人用户开户接口(后台版) + * 用于在本平台系统下为个人用户开户。开户时,会有实名验证和身份证OCR验证,请提供真实信息。 + * 本接口只能用于一级市场的卖家户、分销员户的开户。开通的用户只具有收款能力(藏品卖家),不具有付款能力。 + * + * @throws BizException + * @throws ParamsException + * + * @see https://hfpay.cloudpnr.com/customers/nft/#/levelOneOpenAccount/personalOpenAccount + 返回码 + A40001 省份地区信息非法 + A40002 该用户已开户,身份证号已存在 + A40004 黑名单用户,开户失败 + A40005 身份校验失败 + A40006 身份证格式校验失败 + A40007 身份证末位校验失败 + A40008 手续费配置异常 + A40085 该证件用户开户请求正在处理中,请稍后再试 + A40218 附件编号不存在 + A40219 缺少附件信息 + A40220 开户服务费收取失败 + A40211 user_id不能重复开户 + A40212 身份证开户数超过最大限制 + A40203 用户已开户,无需再提交开户 + A40210 年龄不符合要求 + A40223 身份证附件识别不一致 + A40224 身份证OCR失败 + */ + public function personalCreate( PersonalRequest $params) : PersonalResponse + { + $request = $params->toParams(); + + $data = $this->post('/api/acou/user08', $request); + + if(!$data->isSuccess()) { + throw new BizException('一级市场-个人用户开户创建失败', $data->getCode()); + } + return PersonalResponse::make($data->getBody()); + } + + /** + * 企业用户开户接口(后台版) + * 用于在本平台系统下为个人用户开户。开户时,会有实名验证和身份证OCR验证,请提供真实信息。 + * 本接口只能用于一级市场的卖家户、分销员户的开户。开通的用户只具有收款能力(藏品卖家),不具有付款能力。 + * + * @throws BizException + * @throws ParamsException + * + * @see https://hfpay.cloudpnr.com/customers/nft/#/levelOneOpenAccount/enterpriseOpenAccount + 返回码 + A40001 省份地区信息非法 + A40002 该用户已开户,身份证号已存在 + A40004 黑名单用户,开户失败 + A40005 身份校验失败 + A40006 身份证格式校验失败 + A40007 身份证末位校验失败 + A40009 控股股东不能超过二十个 + A40010 控股股东部分字段为空 + A40011 控股股东部分字段长度超长 + A40012 控股股东证件类型不存在 + A40013 控股股东身份证不合法 + A40014 该企业证照类型与证照号不匹配 + A40015 该申请号已开户 + A40016 该企业营业执照注册号或者社会统一信用码已开户 + A40017 该企业开户申请正在审核中,不能修改 + A40018 该企业开户申请已被拒绝,不能修改 + A40019 该企业开户申请已经通过,不能修改 + A40020 未查询到原开户申请号 + A40021 该申请号已申请开户 + A40022 营业执照注册号或者社会统一信用码已申请开户 + A40023 附件信息不存在 + A40024 附件数量超出10个限制 + A40025 附件文件不存在 + A40026 文件已被使用 + A40027 该记录非待审核状态 + A40028 银行信息不存在 + A40031 原企业开户申请状态为关闭,不能修改 + A40045 审核拒绝,【具体拒绝原因】 + A40046 审核待修改,【具体修改理由】 + A40047 开户成功,绑卡失败,【具体绑卡失败原因】 + A40054 审核状态错误 + H10005 银行卡已存在 + A40102 用户不存在 + A40103 该用户已开户 + A40107 收款方必须开通汇付账户 + A40105 开户请求银行处理中,请勿重复提交 + A40106 请上传文件 + */ + public function companyCreate( CompanyRequest $params) : CompanyResponse + { + $request = $params->toParams(); + + $data = $this->post('/api/acou/corp05', $request); + + if(!$data->isSuccess()) { + throw new BizException('一级市场-企业用户开户创建失败', $data->getCode()); + } + return CompanyResponse::make($data->getBody()); + } + + + /** + * 个体商户开户接口(后台版) + * 用于在本平台系统下为个人用户开户。开户时,会有实名验证和身份证OCR验证,请提供真实信息。 + * 本接口只能用于一级市场的卖家户、分销员户的开户。开通的用户只具有收款能力(藏品卖家),不具有付款能力。 + * + * @throws BizException + * @throws ParamsException + * + * @see https://hfpay.cloudpnr.com/customers/nft/#/levelOneOpenAccount/individualOpenAccount + 返回码 + A40024 附件数量超出10个限制 + A40025 附件文件不存在 + A40026 文件已被使用 + A40027 该记录非待审核状态 + A40028 银行信息不存在 + A40032 该个体工商户开户申请审核已通过,不能修改 + A40033 该个体工商户开户申请正在审核中,不能修改 + A40034 该个体工商户开户申请审核拒绝,不能修改 + A40036 原个体户开户请求不存在 + A40037 该申请号已开户 + A40038 个体户开户申请号已申请开户 + A40039 营业执照注册号已被使用 + A40045 审核拒绝,【具体拒绝原因】 + A40046 审核待修改,【具体修改理由】 + A40047 开户成功,绑卡失败,【具体绑卡失败原因】 + A40054 审核状态错误 + H10005 银行卡已存在 + A40102 用户不存在 + A40103 该用户已开户 + A40107 收款方必须开通汇付账户 + A40105 开户请求银行处理中,请勿重复提交 + A40106 请上传文件 + */ + public function peddlarCreate( PeddlarRequest $params) : PeddlarResponse + { + $request = $params->toParams(); + + $data = $this->post('/api/acou/solo02', $request); + + if(!$data->isSuccess()) { + throw new BizException('一级市场-商户用户开户创建失败', $data->getCode()); + } + return PeddlarResponse::make($data->getBody()); + } + +} \ No newline at end of file diff --git a/src/factory/object/onelevel/CompanyRequest.php b/src/factory/object/onelevel/CompanyRequest.php new file mode 100644 index 0000000..d70f069 --- /dev/null +++ b/src/factory/object/onelevel/CompanyRequest.php @@ -0,0 +1,214 @@ +data['order_date'])) { + throw new ParamsException('订单日期不能为空', 'order_date'); + } + if(empty($this->data['order_id'])) { + throw new ParamsException('订单号不能为空', 'order_id'); + } + + if(empty($this->data['acct_usage_type'])) { + throw new ParamsException('账户用途不能为空', 'acct_usage_type'); + } + + if(empty($this->data['user_id'])) { + throw new ParamsException('用户ID不能为空', 'user_id'); + } + if(empty($this->data['apply_id'])) { + throw new ParamsException('开户申请号不能为空', 'apply_id'); + } + + if(empty($this->data['operate_type'])) { + throw new ParamsException('操作类型不能为空', 'operate_type'); + } + if(!in_array($this->data['operate_type'], [Constant::ONE_COM_OPERATE_TYPE_A, Constant::ONE_COM_OPERATE_TYPE_M])) { + throw new ParamsException('操作类型不正确', 'operate_type'); + } + + if(empty($this->data['corp_license_type'])) { + throw new ParamsException('企业证照类型不能为空', 'corp_license_type'); + } + if(!in_array($this->data['corp_license_type'], [Constant::ONE_COM_CORP_LIS_TYPE_1, Constant::ONE_COM_CORP_LIS_TYPE_2])) { + throw new ParamsException('企业证照类型不正确', 'corp_license_type'); + } + //营业执照 + if($this->data['corp_license_type'] == Constant::ONE_COM_CORP_LIS_TYPE_1) { + if(empty($this->data['business_code'])) { + throw new ParamsException('营业执照注册号不能为空', 'business_code'); + } + if(empty($this->data['institution_code'])) { + throw new ParamsException('组织机构代码不能为空', 'institution_code'); + } + if(empty($this->data['tax_code'])) { + throw new ParamsException('税务登记证号不能为空', 'tax_code'); + } + + } + else + { + //统一社会信用代码 + if(empty($this->data['social_credit_code'])) { + throw new ParamsException('统一社会信用代码不能为空', 'social_credit_code'); + } + + } + + if(empty($this->data['corp_name'])) { + throw new ParamsException('企业名称不能为空', 'corp_name'); + } + + if(empty($this->data['license_start_date'])) { + throw new ParamsException('证照起始日期不能为空', 'license_start_date'); + } + if(empty($this->data['license_end_date'])) { + throw new ParamsException('证照结束日期不能为空', 'license_end_date'); + } + if(empty($this->data['corp_business_address'])) { + throw new ParamsException('企业经营地址不能为空', 'corp_business_address'); + } + if(empty($this->data['corp_reg_address'])) { + throw new ParamsException('企业注册地址不能为空', 'corp_reg_address'); + } + if(empty($this->data['corp_fixed_telephone'])) { + throw new ParamsException('企业固定电话不能为空', 'corp_fixed_telephone'); + } + if(empty($this->data['business_scope'])) { + throw new ParamsException('经营范围不能为空', 'business_scope'); + } + if(empty($this->data['controlling_shareholder'])) { + throw new ParamsException('控股股东(实际控制人)不能为空', 'controlling_shareholder'); + } + $this->data['controlling_shareholder'] = json_encode($this->data['controlling_shareholder'], JSON_UNESCAPED_UNICODE); + + if(empty($this->data['legal_name'])) { + throw new ParamsException('法人姓名不能为空', 'legal_name'); + } + + if(empty($this->data['legal_id_card_type'])) { + throw new ParamsException('法人证件类型不能为空', 'legal_id_card_type'); + } + + if(empty($this->data['legal_id_card'])) { + throw new ParamsException('法人证件号码不能为空', 'legal_id_card'); + } + + if(empty($this->data['legal_cert_start_date'])) { + throw new ParamsException('法人证件起始日期不能为空', 'legal_cert_start_date'); + } + if(empty($this->data['legal_cert_end_date'])) { + throw new ParamsException('法人证件截止日期不能为空', 'legal_cert_end_date'); + } + if(empty($this->data['legal_mobile'])) { + throw new ParamsException('法人手机号码不能为空', 'legal_mobile'); + } + + if(empty($this->data['contact_name'])) { + throw new ParamsException('企业联系人姓名不能为空', 'contact_name'); + } + if(empty($this->data['contact_mobile'])) { + throw new ParamsException('联系人手机号不能为空', 'contact_mobile'); + } + if(empty($this->data['contact_email'])) { + throw new ParamsException('联系人邮箱不能为空', 'contact_email'); + } + + if(empty($this->data['bank_acct_name'])) { + throw new ParamsException('开户银行账户名不能为空', 'bank_acct_name'); + } + // 银行ID号 5000多个 + //https://cloudpnrcdn.oss-cn-shanghai.aliyuncs.com/hfpay/hfpay-excon-web/customers/nft/resources/%E5%8F%96%E7%8E%B0%E6%94%AF%E6%8C%81%E7%9A%84%E9%93%B6%E8%A1%8C%E4%BF%A1%E6%81%AF.xlsx + if(empty($this->data['bank_id'])) { + throw new ParamsException('开户银行代号不能为空', 'bank_id'); + } + if(empty($this->data['bank_acct_num'])) { + throw new ParamsException('开户银行账号不能为空', 'bank_acct_num'); + } + if(empty($this->data['bank_branch'])) { + throw new ParamsException('开户银行支行名称不能为空', 'bank_branch'); + } + if(empty($this->data['bank_prov'])) { + throw new ParamsException('开户银行省份不能为空', 'bank_prov'); + } + if(empty($this->data['bank_area'])) { + throw new ParamsException('开户银行地区不能为空', 'bank_area'); + } + if(empty($this->data['industry'])) { + throw new ParamsException('企业行业类别不能为空', 'industry'); + } + if(!empty($this->data['bg_ret_url'])) { + StrFilterHelper::fileUrl($this->data['bg_ret_url']); + } + if(empty($this->data['attach_nos'])) { + throw new ParamsException('附件信息不能为空', 'attach_nos'); + } + if(empty($this->data['mer_priv'])) { + throw new ParamsException('商户私有域不能为空', 'mer_priv'); + } + if(empty($this->data['extension'])) { + throw new ParamsException('扩展域不能为空', 'extension'); + } + if(empty($this->data['legal_nationality'])) { + throw new ParamsException('法人国籍不能为空', 'legal_nationality'); + } + + + return $this->data; + } +} \ No newline at end of file diff --git a/src/factory/object/onelevel/CompanyResponse.php b/src/factory/object/onelevel/CompanyResponse.php new file mode 100644 index 0000000..4f7d544 --- /dev/null +++ b/src/factory/object/onelevel/CompanyResponse.php @@ -0,0 +1,14 @@ +data['order_date'])) { + throw new ParamsException('订单日期不能为空', 'order_date'); + } + if (empty($this->data['order_id'])) { + throw new ParamsException('订单号不能为空', 'order_id'); + } + if (empty($this->data['acct_usage_type'])) { + throw new ParamsException('账户用途不能为空', 'acct_usage_type'); + } + if (empty($this->data['user_id'])) { + throw new ParamsException('用户ID不能为空', 'user_id'); + } + if (empty($this->data['apply_id'])) { + throw new ParamsException('开户申请号不能为空', 'apply_id'); + } + if(empty($this->data['operate_type'])) { + throw new ParamsException('操作类型不能为空', 'operate_type'); + } + if(!in_array($this->data['operate_type'], [Constant::ONE_COM_OPERATE_TYPE_A, Constant::ONE_COM_OPERATE_TYPE_M])) { + throw new ParamsException('操作类型不正确', 'operate_type'); + } + if (empty($this->data['solo_name'])) { + throw new ParamsException('个体户名称不能为空', 'solo_name'); + } + if (empty($this->data['business_code'])) { + throw new ParamsException('营业执照注册号不能为空', 'business_code'); + } + if (empty($this->data['license_start_date'])) { + throw new ParamsException('证照起始日期不能为空', 'license_start_date'); + } + if (empty($this->data['license_end_date'])) { + throw new ParamsException('证照结束日期不能为空', 'license_end_date'); + } + if (empty($this->data['solo_business_address'])) { + throw new ParamsException('个体户经营地址不能为空', 'solo_business_address'); + } + if (empty($this->data['solo_reg_address'])) { + throw new ParamsException('个体户注册地址不能为空', 'solo_reg_address'); + } + if (empty($this->data['solo_fixed_telephone'])) { + throw new ParamsException('个体户固定电话不能为空', 'solo_fixed_telephone'); + } + if (empty($this->data['business_scope'])) { + throw new ParamsException('经营范围不能为空', 'business_scope'); + } + if (empty($this->data['legal_name'])) { + throw new ParamsException('法人姓名不能为空', 'legal_name'); + } + if (empty($this->data['legal_id_card_type'])) { + throw new ParamsException('法人证件类型不能为空', 'legal_id_card_type'); + } + if (empty($this->data['legal_id_card'])) { + throw new ParamsException('法人证件号码不能为空', 'legal_id_card'); + } + if (empty($this->data['legal_cert_start_date'])) { + throw new ParamsException('法人证件起始日期不能为空', 'legal_cert_start_date'); + } + if (empty($this->data['legal_cert_end_date'])) { + throw new ParamsException('法人证件截止日期不能为空', 'legal_cert_end_date'); + } + if (empty($this->data['legal_mobile'])) { + throw new ParamsException('法人手机号码不能为空', 'legal_mobile'); + } + if (empty($this->data['contact_name'])) { + throw new ParamsException('企业联系人姓名不能为空', 'contact_name'); + } + if (empty($this->data['contact_mobile'])) { + throw new ParamsException('联系人手机号不能为空', 'contact_mobile'); + } + if (empty($this->data['contact_email'])) { + throw new ParamsException('联系人邮箱不能为空', 'contact_email'); + } + if (empty($this->data['occupation'])) { + throw new ParamsException('职业不能为空', 'occupation'); + } + + if (empty($this->data['bank_acct_num'])) { + throw new ParamsException('银行卡号不能为空', 'bank_acct_num'); + } + if (empty($this->data['bank_prov'])) { + throw new ParamsException('省份不能为空', 'bank_prov'); + } + if (empty($this->data['bank_area'])) { + throw new ParamsException('地区不能为空', 'bank_area'); + } + + if (empty($this->data['legal_nationality'])) { + throw new ParamsException('法人国籍不能为空', 'legal_nationality'); + } + + if(empty($this->data['attach_nos'])) { + throw new ParamsException('附件信息不能为空', 'attach_nos'); + } + if(empty($this->data['mer_priv'])) { + throw new ParamsException('商户私有域不能为空', 'mer_priv'); + } + if(empty($this->data['extension'])) { + throw new ParamsException('扩展域不能为空', 'extension'); + } + if(!empty($this->data['bg_ret_url'])) { + StrFilterHelper::fileUrl($this->data['bg_ret_url']); + } + + return $this->data; + } +} \ No newline at end of file diff --git a/src/factory/object/onelevel/PeddlarResponse.php b/src/factory/object/onelevel/PeddlarResponse.php new file mode 100644 index 0000000..7246e0f --- /dev/null +++ b/src/factory/object/onelevel/PeddlarResponse.php @@ -0,0 +1,14 @@ +data['order_date'])) { + throw new ParamsException('订单日期不能为空', 'order_date'); + } + if(empty($this->data['order_id'])) { + throw new ParamsException('订单号不能为空', 'order_id'); + } + + if(empty($this->data['acct_usage_type'])) { + throw new ParamsException('账户用途不能为空', 'acct_usage_type'); + } + + if(empty($this->data['user_id'])) { + throw new ParamsException('用户ID不能为空', 'user_id'); + } + + if(empty($this->data['user_name'])) { + throw new ParamsException('用户姓名不能为空', 'user_name'); + } + + if(empty($this->data['id_card'])) { + throw new ParamsException('证件号不能为空', 'id_card'); + } + if(empty($this->data['id_card_type'])) { + throw new ParamsException('证件类型不能为空', 'id_card_type'); + } + if(!in_array($this->data['id_card_type'], [Constant::ID_TYPE_CARD])) { + throw new ParamsException('证件类型不支持', 'id_card_type'); + } + if(empty($this->data['user_mobile'])) { + throw new ParamsException('手机号不能为空', 'user_mobile'); + } + if(empty($this->data['occupation'])) { + throw new ParamsException('职业不能为空', 'occupation'); + } + if(empty($this->data['card_num'])) { + throw new ParamsException('银行卡号不能为空', 'card_num'); + } + if(empty($this->data['attach_nos'])) { + throw new ParamsException('附件信息不能为空', 'attach_nos'); + } + if(empty($this->data['mer_priv'])) { + throw new ParamsException('商户私有域不能为空', 'mer_priv'); + } + if(empty($this->data['extension'])) { + throw new ParamsException('扩展域不能为空', 'extension'); + } + if(!empty($this->data['bg_ret_url'])) { + StrFilterHelper::fileUrl($this->data['bg_ret_url']); + } + + return $this->data; + } +} \ No newline at end of file diff --git a/src/factory/object/onelevel/PersonalResponse.php b/src/factory/object/onelevel/PersonalResponse.php new file mode 100644 index 0000000..823e8b6 --- /dev/null +++ b/src/factory/object/onelevel/PersonalResponse.php @@ -0,0 +1,13 @@ +data['attach_no'])) { + throw new ParamsException('附件编号不能为空', 'attach_no'); + } + if(empty($this->data['trans_type'])) { + throw new ParamsException('业务类型不能为空', 'trans_type'); + } + if(empty($this->data['attach_type'])) { + throw new ParamsException('附件类型不能为空', 'attach_type'); + } + if(empty($this->data['attach_desc'])) { + throw new ParamsException('文件描述不能为空', 'attach_desc'); + } + + if(empty($this->data['attach_file'])) { + throw new ParamsException('文件不能为空', 'attach_file'); + } + if(empty($this->data['handle_type'])) { + throw new ParamsException('上传类型不能为空', 'handle_type'); + } + + + return $this->data; + } +} \ No newline at end of file diff --git a/src/factory/object/onelevel/UploadResponse.php b/src/factory/object/onelevel/UploadResponse.php new file mode 100644 index 0000000..090fac6 --- /dev/null +++ b/src/factory/object/onelevel/UploadResponse.php @@ -0,0 +1,13 @@ + Date: Thu, 4 Jun 2026 18:15:28 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/factory/object/RequestObj.php | 2 +- src/factory/object/ResponseObj.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/factory/object/RequestObj.php b/src/factory/object/RequestObj.php index 36a9950..6497a8b 100644 --- a/src/factory/object/RequestObj.php +++ b/src/factory/object/RequestObj.php @@ -4,7 +4,7 @@ namespace Tansilu\HfPayLib\factory\object; trait RequestObj { - private array $data; + private array $data = []; public function __set($name, $value) { diff --git a/src/factory/object/ResponseObj.php b/src/factory/object/ResponseObj.php index bf334b1..97c8b03 100644 --- a/src/factory/object/ResponseObj.php +++ b/src/factory/object/ResponseObj.php @@ -11,7 +11,7 @@ trait ResponseObj return $self; } - private array $data; + private array $data = []; public function __get($name) { From 932ca477547d61e157eb85ab69bd5f43d6005900 Mon Sep 17 00:00:00 2001 From: JING Date: Thu, 4 Jun 2026 18:21:38 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E8=BF=94=E5=9B=9EContent-Type=20=E9=BB=98=E8=AE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/http/Response.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/http/Response.php b/src/http/Response.php index fcbad98..8c5555d 100644 --- a/src/http/Response.php +++ b/src/http/Response.php @@ -29,7 +29,9 @@ class Response if(!empty($self->source)) { $contentType = $response->getHeader('Content-Type'); if(empty($contentType)) { - throw new ApiException('反馈的消息未指明内容格式Content-Type'); + //throw new ApiException('反馈的消息未指明内容格式Content-Type'); + //如果没有默认为这个 + $contentType[0] = 'application/json; charset=utf-8'; } $bodyFormat = explode(';', $contentType[0]); switch ($bodyFormat[0]) { From 6abef5214e4e2148f666847ae294ba5145b23b11 Mon Sep 17 00:00:00 2001 From: JING Date: Fri, 5 Jun 2026 15:36:58 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E6=B1=87=E4=BB=98=E8=A7=84=E5=AE=9A?= =?UTF-8?q?=E9=9D=9E=E5=BF=85=E5=A1=AB=E9=A1=B9=E4=B8=8D=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../object/onelevel/CompanyRequest.php | 16 ++++++------- .../object/onelevel/PeddlarRequest.php | 24 ++++++++++--------- .../object/onelevel/PersonalRequest.php | 8 +++---- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/factory/object/onelevel/CompanyRequest.php b/src/factory/object/onelevel/CompanyRequest.php index d70f069..22f4434 100644 --- a/src/factory/object/onelevel/CompanyRequest.php +++ b/src/factory/object/onelevel/CompanyRequest.php @@ -114,7 +114,7 @@ class CompanyRequest throw new ParamsException('企业名称不能为空', 'corp_name'); } - if(empty($this->data['license_start_date'])) { + /* if(empty($this->data['license_start_date'])) { throw new ParamsException('证照起始日期不能为空', 'license_start_date'); } if(empty($this->data['license_end_date'])) { @@ -131,7 +131,7 @@ class CompanyRequest } if(empty($this->data['business_scope'])) { throw new ParamsException('经营范围不能为空', 'business_scope'); - } + }*/ if(empty($this->data['controlling_shareholder'])) { throw new ParamsException('控股股东(实际控制人)不能为空', 'controlling_shareholder'); } @@ -180,25 +180,25 @@ class CompanyRequest if(empty($this->data['bank_acct_num'])) { throw new ParamsException('开户银行账号不能为空', 'bank_acct_num'); } - if(empty($this->data['bank_branch'])) { + /*if(empty($this->data['bank_branch'])) { throw new ParamsException('开户银行支行名称不能为空', 'bank_branch'); - } + }*/ if(empty($this->data['bank_prov'])) { throw new ParamsException('开户银行省份不能为空', 'bank_prov'); } if(empty($this->data['bank_area'])) { throw new ParamsException('开户银行地区不能为空', 'bank_area'); } - if(empty($this->data['industry'])) { + /* if(empty($this->data['industry'])) { throw new ParamsException('企业行业类别不能为空', 'industry'); - } + }*/ if(!empty($this->data['bg_ret_url'])) { StrFilterHelper::fileUrl($this->data['bg_ret_url']); } if(empty($this->data['attach_nos'])) { throw new ParamsException('附件信息不能为空', 'attach_nos'); } - if(empty($this->data['mer_priv'])) { + /*if(empty($this->data['mer_priv'])) { throw new ParamsException('商户私有域不能为空', 'mer_priv'); } if(empty($this->data['extension'])) { @@ -206,7 +206,7 @@ class CompanyRequest } if(empty($this->data['legal_nationality'])) { throw new ParamsException('法人国籍不能为空', 'legal_nationality'); - } + }*/ return $this->data; diff --git a/src/factory/object/onelevel/PeddlarRequest.php b/src/factory/object/onelevel/PeddlarRequest.php index 470dc88..a4fdc98 100644 --- a/src/factory/object/onelevel/PeddlarRequest.php +++ b/src/factory/object/onelevel/PeddlarRequest.php @@ -85,9 +85,9 @@ class PeddlarRequest if (empty($this->data['solo_business_address'])) { throw new ParamsException('个体户经营地址不能为空', 'solo_business_address'); } - if (empty($this->data['solo_reg_address'])) { + /*if (empty($this->data['solo_reg_address'])) { throw new ParamsException('个体户注册地址不能为空', 'solo_reg_address'); - } + }*/ if (empty($this->data['solo_fixed_telephone'])) { throw new ParamsException('个体户固定电话不能为空', 'solo_fixed_telephone'); } @@ -125,7 +125,16 @@ class PeddlarRequest throw new ParamsException('职业不能为空', 'occupation'); } - if (empty($this->data['bank_acct_num'])) { + + if(empty($this->data['attach_nos'])) { + throw new ParamsException('附件信息不能为空', 'attach_nos'); + } + + if(!empty($this->data['bg_ret_url'])) { + StrFilterHelper::fileUrl($this->data['bg_ret_url']); + } + + /*if (empty($this->data['bank_acct_num'])) { throw new ParamsException('银行卡号不能为空', 'bank_acct_num'); } if (empty($this->data['bank_prov'])) { @@ -138,19 +147,12 @@ class PeddlarRequest if (empty($this->data['legal_nationality'])) { throw new ParamsException('法人国籍不能为空', 'legal_nationality'); } - - if(empty($this->data['attach_nos'])) { - throw new ParamsException('附件信息不能为空', 'attach_nos'); - } if(empty($this->data['mer_priv'])) { throw new ParamsException('商户私有域不能为空', 'mer_priv'); } if(empty($this->data['extension'])) { throw new ParamsException('扩展域不能为空', 'extension'); - } - if(!empty($this->data['bg_ret_url'])) { - StrFilterHelper::fileUrl($this->data['bg_ret_url']); - } + }*/ return $this->data; } diff --git a/src/factory/object/onelevel/PersonalRequest.php b/src/factory/object/onelevel/PersonalRequest.php index 487a44c..c848d47 100644 --- a/src/factory/object/onelevel/PersonalRequest.php +++ b/src/factory/object/onelevel/PersonalRequest.php @@ -67,21 +67,21 @@ class PersonalRequest if(empty($this->data['user_mobile'])) { throw new ParamsException('手机号不能为空', 'user_mobile'); } - if(empty($this->data['occupation'])) { - throw new ParamsException('职业不能为空', 'occupation'); - } if(empty($this->data['card_num'])) { throw new ParamsException('银行卡号不能为空', 'card_num'); } if(empty($this->data['attach_nos'])) { throw new ParamsException('附件信息不能为空', 'attach_nos'); } + /*if(empty($this->data['occupation'])) { + throw new ParamsException('职业不能为空', 'occupation'); + } if(empty($this->data['mer_priv'])) { throw new ParamsException('商户私有域不能为空', 'mer_priv'); } if(empty($this->data['extension'])) { throw new ParamsException('扩展域不能为空', 'extension'); - } + }*/ if(!empty($this->data['bg_ret_url'])) { StrFilterHelper::fileUrl($this->data['bg_ret_url']); } From 25687e8b2c8fb914ef4aa17d5d452ba9f5a6de59 Mon Sep 17 00:00:00 2001 From: JING Date: Mon, 15 Jun 2026 12:35:30 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86post=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E6=96=87=E4=BB=B6=E7=9A=84=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/factory/impl/OneLevelFactory.php | 4 +-- src/factory/object/RequestObj.php | 2 +- src/factory/object/onelevel/UploadRequest.php | 31 ++++++++++++++++++- src/http/Factory.php | 4 +++ src/http/IHttpClient.php | 3 ++ src/http/Response.php | 1 - src/http/impl/HFPayHttpClient.php | 18 +++++++++++ 7 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/factory/impl/OneLevelFactory.php b/src/factory/impl/OneLevelFactory.php index 816d79b..e46c124 100644 --- a/src/factory/impl/OneLevelFactory.php +++ b/src/factory/impl/OneLevelFactory.php @@ -56,11 +56,11 @@ class OneLevelFactory extends BaseFactory { $request = $params->toParams(); - $data = $this->post('/api/alseFile/file01', $request); - + $data = $this->uploadPost('/api/alseFile/file01', $request); if(!$data->isSuccess()) { throw new BizException('上传失败', $data->getCode()); } + return UploadResponse::make($data->getBody()); } /** diff --git a/src/factory/object/RequestObj.php b/src/factory/object/RequestObj.php index 6497a8b..32423ff 100644 --- a/src/factory/object/RequestObj.php +++ b/src/factory/object/RequestObj.php @@ -4,7 +4,7 @@ namespace Tansilu\HfPayLib\factory\object; trait RequestObj { - private array $data = []; + private array $data =[]; public function __set($name, $value) { diff --git a/src/factory/object/onelevel/UploadRequest.php b/src/factory/object/onelevel/UploadRequest.php index 89e4949..3a82480 100644 --- a/src/factory/object/onelevel/UploadRequest.php +++ b/src/factory/object/onelevel/UploadRequest.php @@ -67,7 +67,36 @@ class UploadRequest throw new ParamsException('上传类型不能为空', 'handle_type'); } + // 构建 multipart 数据结构 + $multipartData = [ + [ + 'name' => 'attach_file', // 这里的 'file' 是接口定义的文件字段名 + 'contents' => fopen($this->data['attach_file'], 'r'), // 使用 fopen 打开文件流 + ], + // 可以同时上传其他文本字段 + [ + 'name' => 'attach_no', + 'contents' => $this->data['attach_no'], + ], + [ + 'name' => 'trans_type', + 'contents' => $this->data['trans_type'], + ], + [ + 'name' => 'attach_type', + 'contents' => $this->data['attach_type'], + ], + [ + 'name' => 'attach_desc', + 'contents' => $this->data['attach_desc'], + ], + [ + 'name' => 'handle_type', + 'contents' => $this->data['handle_type'], + ], + ]; - return $this->data; + + return $multipartData; } } \ No newline at end of file diff --git a/src/http/Factory.php b/src/http/Factory.php index f91b99b..c9ba83f 100644 --- a/src/http/Factory.php +++ b/src/http/Factory.php @@ -44,4 +44,8 @@ class Factory { return $this->client->postJson($url, $data); } + public function uploadPost(string $url, array $data = []): Response + { + return $this->client->uploadPost($url, $data); + } } \ No newline at end of file diff --git a/src/http/IHttpClient.php b/src/http/IHttpClient.php index 5dee64e..5d2a0b2 100644 --- a/src/http/IHttpClient.php +++ b/src/http/IHttpClient.php @@ -18,4 +18,7 @@ interface IHttpClient function postJson(string $uri, ?array $data = []): Response; + function uploadPost(string $uri, ?array $data = []): Response; + + } \ No newline at end of file diff --git a/src/http/Response.php b/src/http/Response.php index 8c5555d..a420d86 100644 --- a/src/http/Response.php +++ b/src/http/Response.php @@ -30,7 +30,6 @@ class Response $contentType = $response->getHeader('Content-Type'); if(empty($contentType)) { //throw new ApiException('反馈的消息未指明内容格式Content-Type'); - //如果没有默认为这个 $contentType[0] = 'application/json; charset=utf-8'; } $bodyFormat = explode(';', $contentType[0]); diff --git a/src/http/impl/HFPayHttpClient.php b/src/http/impl/HFPayHttpClient.php index fc6c3ff..8286b23 100644 --- a/src/http/impl/HFPayHttpClient.php +++ b/src/http/impl/HFPayHttpClient.php @@ -166,6 +166,10 @@ class HFPayHttpClient implements IHttpClient case 'body': $options['body'] = array_filter($body, fn($v) => $v !== null); break; + // 新增的分支 + case 'multipart': + $options['multipart'] = array_filter($body, fn($v) => $v !== null); + break; } try { @@ -273,4 +277,18 @@ class HFPayHttpClient implements IHttpClient { return $this->request('POST', $uri, [], $data, 'json', $needToken); } + /** + * 上传文件 + * @param string $uri + * @param array|null $data + * @return Response + * @throws ApiException + * @throws BizException + * @throws SignException + */ + function uploadPost(string $uri, ?array $data = []): Response + { + // 调用 request,并指定格式为 'multipart' + return $this->request('POST', $uri, [], $data, 'multipart'); + } } \ No newline at end of file From 348de5cb19427f73a4068edb6f3cd0fb8ba500de Mon Sep 17 00:00:00 2001 From: JING Date: Mon, 15 Jun 2026 16:35:40 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/factory/object/onelevel/UploadRequest.php | 33 +---- src/http/impl/HFPayHttpClient.php | 136 +++++++++++++----- 2 files changed, 99 insertions(+), 70 deletions(-) diff --git a/src/factory/object/onelevel/UploadRequest.php b/src/factory/object/onelevel/UploadRequest.php index 3a82480..cc87528 100644 --- a/src/factory/object/onelevel/UploadRequest.php +++ b/src/factory/object/onelevel/UploadRequest.php @@ -66,37 +66,6 @@ class UploadRequest if(empty($this->data['handle_type'])) { throw new ParamsException('上传类型不能为空', 'handle_type'); } - - // 构建 multipart 数据结构 - $multipartData = [ - [ - 'name' => 'attach_file', // 这里的 'file' 是接口定义的文件字段名 - 'contents' => fopen($this->data['attach_file'], 'r'), // 使用 fopen 打开文件流 - ], - // 可以同时上传其他文本字段 - [ - 'name' => 'attach_no', - 'contents' => $this->data['attach_no'], - ], - [ - 'name' => 'trans_type', - 'contents' => $this->data['trans_type'], - ], - [ - 'name' => 'attach_type', - 'contents' => $this->data['attach_type'], - ], - [ - 'name' => 'attach_desc', - 'contents' => $this->data['attach_desc'], - ], - [ - 'name' => 'handle_type', - 'contents' => $this->data['handle_type'], - ], - ]; - - - return $multipartData; + return $this->data; } } \ No newline at end of file diff --git a/src/http/impl/HFPayHttpClient.php b/src/http/impl/HFPayHttpClient.php index 8286b23..53bebee 100644 --- a/src/http/impl/HFPayHttpClient.php +++ b/src/http/impl/HFPayHttpClient.php @@ -114,7 +114,61 @@ class HFPayHttpClient implements IHttpClient */ private ISigner $signClient; + /** + * 准备 Multipart 数据 + * 核心原则:文件流只进 multipart,不进 signData;文本字段两者都进 + */ + private function _prepareMultipartData(array $body): array + { + $multipart = []; + $signData = []; + + foreach ($body as $key => $value) { + // 1. 资源类型(文件流):仅放入 multipart,绝不参与签名 + if (is_resource($value)) { + $multipart[] = [ + 'name' => $key, + 'contents' => $value, + ]; + continue; + } + + // 2. 已是 Guzzle Multipart 格式的数组 + if (is_array($value) && isset($value['contents'])) { + $multipart[] = $value; + // 仅当 contents 非资源时才参与签名 + if (!is_resource($value['contents'])) { + $signData[$key] = (string)$value['contents']; + } + continue; + } + + // 3. 普通数组:转 JSON 字符串 + if (is_array($value)) { + $jsonStr = json_encode($value, JSON_UNESCAPED_UNICODE); + $multipart[] = ['name' => $key, 'contents' => $jsonStr]; + $signData[$key] = $jsonStr; + continue; + } + // 4. NULL 值:转为空字符串(汇付通常要求空值也参与签名) + if ($value === null) { + $multipart[] = ['name' => $key, 'contents' => '']; + $signData[$key] = ''; + continue; + } + + // 5. 标量类型:强制转为字符串 + $strVal = (string)$value; + $multipart[] = ['name' => $key, 'contents' => $strVal]; + $signData[$key] = $strVal; + } + + return [ + 'multipart' => $multipart, + 'sign_data' => $signData, + ]; + } /** * @param string $method * @param string $uri @@ -131,64 +185,70 @@ class HFPayHttpClient implements IHttpClient { $options = $this->getRequestOptions(); - if(!empty($query)) { + if (!empty($query)) { $options['query'] = array_filter($query, fn($v) => $v !== null); } - //添加固定的参数 - //版本号 - if(empty($body['version'])) { - $body['version'] = $this->config['version'] ?? ''; + + // ✅ 关键修正:固定参数必须在签名之前注入到 $body 中 + // 这样无论是 form/json 还是 multipart,都能保证这些字段参与签名 + if (empty($body['version'])) { + $body['version'] = $this->config['version'] ?? self::API_VERSION; } - if(empty($body['mer_cust_id'])) { + if (empty($body['mer_cust_id'])) { $body['mer_cust_id'] = $this->config['mid'] ?? ''; } - if(empty($body['bg_ret_url']) && !empty($this->config['callback'])) { + if (empty($body['bg_ret_url']) && !empty($this->config['callback'])) { $body['bg_ret_url'] = $this->config['callback']; } - //将内容生成签名 - $sign = $this->signClient->sign($body); - $body['check_value'] = $sign; + if ($format === 'multipart') { + // 1. 分离文件流和文本参数 + $processed = $this->_prepareMultipartData($body); -// echo '请求参数 #####'; -// print_r($body); -// echo '请求参数 end'; - if(empty($format)) { - $format = 'form'; - } - switch ($format) { - case 'json': - $options['json'] = array_filter($body, fn($v) => $v !== null); - break; - case 'form': - $options['form_params'] = array_filter($body, fn($v) => $v !== null); - break; - case 'body': - $options['body'] = array_filter($body, fn($v) => $v !== null); - break; - // 新增的分支 - case 'multipart': - $options['multipart'] = array_filter($body, fn($v) => $v !== null); - break; - } + // 2. 使用纯文本参数生成签名(文件流已被排除) + $sign = $this->signClient->sign($processed['sign_data']); + + // 3. 将签名结果作为普通文本字段追加到 multipart + $processed['multipart'][] = [ + 'name' => 'check_value', + 'contents' => $sign, + ]; + + $options['multipart'] = $processed['multipart']; + } else { + // 非 multipart 逻辑保持不变 + $sign = $this->signClient->sign($body); + $body['check_value'] = $sign; + switch ($format) { + case 'json': + $options['json'] = array_filter($body, fn($v) => $v !== null); + break; + case 'form': + $options['form_params'] = array_filter($body, fn($v) => $v !== null); + break; + case 'body': + $options['body'] = json_encode(array_filter($body, fn($v) => $v !== null), JSON_UNESCAPED_UNICODE); + break; + } + } try { $resp = $this->client->request($method, $uri, $options); } catch (GuzzleException $e) { throw new ApiException($e->getMessage()); } - $response = Response::make($resp); - if(!$response->isSuccess()) { + $response = Response::make($resp); + if (!$response->isSuccess()) { throw new ApiException('汇付反馈状态不正确', $resp->getStatusCode()); } - //验证数据 - $body = $response->getBody(); - if(!$this->signClient->verify($body)) { + + $respBody = $response->getBody(); + if (!$this->signClient->verify($respBody)) { throw new ApiException('签名验证未通过'); } - //解码 - $decodeBody = $this->signClient->decode($body['check_value']); + + $decodeBody = $this->signClient->decode($respBody['check_value']); ErrCodeHelper::parseError($decodeBody['resp_code'], $decodeBody['resp_desc']); return Response::tempInit(200, $decodeBody); } From a42093fa502f06eadb447f5cfe867d099573b195 Mon Sep 17 00:00:00 2001 From: "X14XA\\shengli" Date: Tue, 23 Jun 2026 18:06:11 +0800 Subject: [PATCH 7/7] 0.0.12 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8aa085a..fb76afe 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "tansilu/hfpay-lib", - "version": "0.0.11", + "version": "0.0.12", "type": "library", "require": { "php": ">=7.4",