first commit

This commit is contained in:
annnj-company
2026-04-17 18:29:53 +08:00
parent e49fa5a215
commit 130c1026c4
5615 changed files with 1639145 additions and 0 deletions

View File

@@ -0,0 +1,467 @@
<?php
namespace app\lib;
use app\util\ReturnCode;
use think\facade\Env;
use \Exception;
/**
* 权限系统接口
*/
class AuthApi
{
//调用信息
// const USERNAME = 'auth';
const USERNAME = 'nce';
// const PASSWORD = 'YlzXZbm4&5';
const PASSWORD = 'NRXpT@HfvH';
const GRANT_TYPE = 'refresh_token';
// 接口IP
//const AUTH_URL = 'http://106.52.70.137:8080/';
// const AUTH_URL = 'http://111.230.221.71:8001/';
// const AUTH_URL = 'http://129.204.123.130:8001/'; // uat
private $auth_url;
//接口地址
const API_TOKEN = 'auth/oauth/token'; //获取token接口/刷新token接口
const API_TOKEN1 = 'oauth/token'; //获取token接口/刷新token接口
const API_DEL_TOKEN = '/logout'; //注销token接口
const API_USER_AUTH = 'auth/api/user/per'; //获取用户权限
const API_USER_ROLE = 'auth/api/user/role'; //获取角色用户
const API_USER_LIST = 'auth/api/user/list'; //获取用户列表
const API_DEPART_ROLE = 'auth/api/user/depart/users'; //根据部门id获取用户信息
const API_BUSINESS_DEPARTMENT = 'auth/api/user/depart'; //根据业务部id获取业务部下属所有分部信息
const API_MANY_USER_ROLE = 'auth/api/user/roles'; //获取多角色用户
const API_QR_CODE = 'auth/user/token'; // 扫码登录获取token接口
const API_UPDATE_PWD = 'system/user/profile/updatePwd'; // 扫码登录获取token接口
// const API_TOKEN = 'CLOUD-AUTH/oauth/token'; //获取token接口/刷新token接口
// const API_TOKEN1 = 'oauth/token'; //获取token接口/刷新token接口
// const API_DEL_TOKEN = 'CLOUD-AUTH/api/exit'; //注销token接口
// const API_USER_AUTH = 'CLOUD-AUTH/api/user/per'; //获取用户权限
// const API_USER_ROLE = 'CLOUD-AUTH/api/user/role'; //获取角色用户
// const API_DEPART_ROLE = 'CLOUD-AUTH/api/user/depart/users'; //根据部门id获取用户信息
// const API_BUSINESS_DEPARTMENT = 'CLOUD-AUTH/api/user/depart'; //根据业务部id获取业务部下属所有分部信息
// const API_MANY_USER_ROLE = 'CLOUD-AUTH/api/user/roles'; //获取多角色用户
// const API_QR_CODE = 'CLOUD-AUTH/user/token'; // 扫码登录获取token接口
public function __construct(){
$this->auth_url = Env::get('auth.auth_url');
}
/**
* GET 请求
* @param string $url
*/
private function http_get($url,$param,$arr_header=array(),$id=''){
$oCurl = curl_init();
if (is_string($param)) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
$url = $url."?".$strPOST;
if (stripos($url, "https://") !== false) {
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
}
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
if(!empty($arr_header)){
$arr_header[] = "Content-Type: application/json; charset=utf-8";
}
curl_setopt($oCurl, CURLOPT_HTTPHEADER, $arr_header);
$sContent = curl_exec($oCurl);
if (curl_errno($oCurl)){
throw new Exception(curl_error($oCurl),0);
}else{
$httpStatusCode = curl_getinfo($oCurl, CURLINFO_HTTP_CODE);
if (200 !== $httpStatusCode){
throw new Exception($arr_header[1],$httpStatusCode);
}
}
curl_close($oCurl);
return $sContent;
}
/**
* POST 请求
* @param string $url
* @param array $param
* @param boolean $post_file 是否文件上传
* @param boolean $time 超时时间,单位秒
* @param boolean $id 爬虫日志表id
* @param boolean $arr_header http请求头
* @return string content
*/
private function http_post($url, $param,$user_name,$password, $post_file = false, $time = 30,$id='',$arr_header=array()){
$oCurl = curl_init();
if (stripos($url, "https://") !== false) {
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
if(stripos($url,"pycredit")!== false){
curl_setopt($oCurl, CURLOPT_SSLCERT, APP_PATH . 'extra' . DS . self::PYCERT_NAME); //pem
curl_setopt($oCurl, CURLOPT_SSLCERTPASSWD, '123456');
curl_setopt($oCurl, CURLOPT_SSLKEY, APP_PATH . 'extra' . DS . self::PYCERT_NAME); //pem
curl_setopt($oCurl, CURLOPT_SSLKEYPASSWD, '123456'); //pem
}
}
if (is_string($param) || $post_file) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($oCurl, CURLOPT_POST, true);
curl_setopt($oCurl, CURLOPT_TIMEOUT, $time); //只需要设置一个秒的数量就可以,超时时间
curl_setopt($oCurl, CURLOPT_POSTFIELDS, $strPOST);
// curl_setopt($oCurl, CURLOPT_HTTPHEADER, $arr_header);
curl_setopt($oCurl, CURLOPT_USERPWD, "{$user_name}:{$password}");
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return false;
}
}
/**
* DELETE 请求
* @param string $url
* @param array $param
* @param boolean $user_name AUTH账号
* @param boolean $password AUTH密码
* @return string content
*/
function http_delete($url,$param,$user_name,$password) {
$oCurl = curl_init();
if (is_string($param)) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
$url = $url."?".$strPOST;
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($oCurl, CURLOPT_CUSTOMREQUEST, 'DELETE');
//设置头
curl_setopt($oCurl, CURLOPT_USERPWD, "{$user_name}:{$password}");
curl_setopt($oCurl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36');
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);//SSL认证。
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return false;
}
}
/**
* PUT 请求
* @param string $url
* @param array $param
* @param boolean $user_name AUTH账号
* @param boolean $password AUTH密码
* @return string content
*/
function http_put($url,$param,$user_name,$password, $arr_header) {
$oCurl = curl_init();
if (is_string($param)) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
$url = $url."?".$strPOST;
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($oCurl, CURLOPT_CUSTOMREQUEST, 'PUT');
//设置头
curl_setopt($oCurl, CURLOPT_HTTPHEADER, $arr_header);
// curl_setopt($oCurl, CURLOPT_USERPWD, "{$user_name}:{$password}");
curl_setopt($oCurl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36');
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);//SSL认证。
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return false;
}
}
/**
* getToken
* @Author
* @DateTime
* @version 1.0
* @param data 查询条件json
* @return string 查询结果json字符串
*/
public function getToken($data){
if (empty($data)) {
return ReturnCode::AUTH_PARAMETER;
}
$apiFrom = self::API_TOKEN;
$url = $this->auth_url . $apiFrom;
$user_name = self::USERNAME;
$password = self::PASSWORD;
$res = $this->http_post($url, $data,$user_name,$password, false, 120);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_TOKEN;
}
}
public function getQrCodeToken($data){
if (empty($data)) {
return ReturnCode::AUTH_PARAMETER;
}
$apiFrom = self::API_QR_CODE;
$url = $this->auth_url . $apiFrom;
$user_name = self::USERNAME;
$password = self::PASSWORD;
$res = $this->http_post($url, $data,$user_name,$password, false, 120);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_TOKEN;
}
}
/**
* userinfo
* @Author
* @DateTime
* @version 1.0
* @param data 查询条件
* @return string 查询结果json字符串
*/
public function userinfo($data,$arr_header)
{
if (empty($data)) {
return ReturnCode::AUTH_USER_TOKEN;
}
$apiFrom = self::API_USER_AUTH;
$url = $this->auth_url . $apiFrom;
$res = $this->http_get($url,$data,$arr_header);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_USER;
}
}
/**
* Logout
* @Author llz
* @DateTime 2022-10-10
* @version 1.0
* @param
* @return
*/
public function Logout($data)
{
if (empty($data)) {
return ReturnCode::AUTH_USER_TOKEN;
}
$apiFrom = self::API_DEL_TOKEN;
$url = $this->auth_url . $apiFrom;
$user_name = self::USERNAME;
$password = self::PASSWORD;
$res = $this->http_delete($url,$data,$user_name,$password);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_USER;
}
}
/**
* userinfo
* @Author
* @DateTime
* @version 1.0
* @param data 查询条件
* @return string 查询结果json字符串
*/
public function RefreshgetToken($userid,$refresh_token)
{
if (empty($refresh_token)) {
return ReturnCode::AUTH_PARAMETER;
}
$apiFrom = self::API_TOKEN;
$userInfo = cache('userinfo'.$userid);
$url = $this->auth_url . $apiFrom."?grant_type=".self::GRANT_TYPE."&refresh_token=".$refresh_token;
$user_name = $userInfo['user_name'];
$password = self::PASSWORD;
$res = $this->http_post($url, array(),$user_name,$password, false, 120);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_TOKEN;
}
}
public function getRole($data,$arr_header) {
if (empty($data)) {
return ReturnCode::AUTH_PARAMETER;
}
$apiFrom = self::API_USER_ROLE;
$url = $this->auth_url . $apiFrom;
$res = $this->http_get($url,$data);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_ROLE;
}
}
/**
* 根据部门id获取用户列表
* @param [type] $data [description]
* @return [type] [description]
*/
public function getUsersListById($data) {
if (empty($data)) {
return ReturnCode::AUTH_PARAMETER;
}
$apiFrom = self::API_DEPART_ROLE;
$url = $this->auth_url . $apiFrom;
$res = $this->http_get($url,$data);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_ROLE;
}
}
/**
* 根据业务部id获取业务部下面所有部门信息
* @param $data
* @return array|int
*/
public function getBusinessDepartment($data) {
if (empty($data)) {
return ReturnCode::AUTH_PARAMETER;
}
$apiFrom = self::API_BUSINESS_DEPARTMENT;
$url = $this->auth_url . $apiFrom;
$res = $this->http_get($url,$data);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_ROLE;
}
}
/**
* getUser
* @Author
* @DateTime
* @version 1.0
* @param data 查询条件json
* @return string 查询结果json字符串
*/
public function getUser($data){
if (empty($data)) {
return ReturnCode::AUTH_PARAMETER;
}
$apiFrom = self::API_MANY_USER_ROLE;
$url = $this->auth_url . $apiFrom;
$data['systemCode'] = 'NCE';
$res = $this->http_get($url,$data);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_TOKEN;
}
}
/**
* getUserList
* @Author llz
* @DateTime 2023-3-09
* @version 1.0
* @return string 查询结果json字符串
*/
public function getUserList(){
$url = $this->auth_url . self::API_USER_LIST;
$res = $this->http_get($url,[]);
if ($res) {
return $res;
} else {
return ReturnCode::DB_READ_ERROR;
}
}
/**
* updatePwd
* @Author llz
* @DateTime 2023-3-09
* @version 1.0
* @return string 查询结果json字符串
*/
public function updatePwd(array $data, array $arr_header): string
{
if (empty($data)) {
return ReturnCode::AUTH_PARAMETER;
}
$apiFrom = self::API_UPDATE_PWD;
$url = $this->auth_url . $apiFrom;
$res = $this->http_put($url, $data, self::USERNAME, self::PASSWORD, $arr_header);
if ($res) {
return $res;
} else {
return ReturnCode::AUTH_USER;
}
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace app\lib\BOC;
class BocCipherUtil {
private const ENCODING = 'UTF-8';
private const ALGORITHM_NAME = 'SM4';
private const ALGORITHM_NAME_ECB_PADDING = 'SM4-ECB';
private const DEFAULT_KEY_SIZE = 128;
/**
* 生成ECB模式的SM4加密器/解密器
* @param string $algorithmName 算法名称
* @param int $mode 模式OPENSSL_ENCRYPT或OPENSSL_DECRYPT
* @param string $key 密钥
* @return array 加密/解密参数
*/
private static function generateEcbCipher($algorithmName, $mode, $key) {
return [
'cipher' => $algorithmName,
'key' => $key,
'options' => OPENSSL_RAW_DATA,
'iv' => '' // ECB模式不需要IV
];
}
/**
* 生成SM4密钥
* @param int $keySize 密钥大小
* @return string 随机密钥
*/
public static function generateKey($keySize = self::DEFAULT_KEY_SIZE) {
return openssl_random_pseudo_bytes($keySize / 8);
}
/**
* SM4 ECB模式加密
* @param string $hexKey 16进制密钥
* @param string $paramStr 待加密字符串
* @return string 16进制加密结果
*/
public static function encryptEcb($hexKey, $paramStr) {
$key = hex2bin($hexKey);
$srcData = $paramStr;
$cipherParams = self::generateEcbCipher(self::ALGORITHM_NAME_ECB_PADDING, OPENSSL_ENCRYPT, $key);
$cipherArray = openssl_encrypt($srcData, $cipherParams['cipher'], $cipherParams['key'], $cipherParams['options'], $cipherParams['iv']);
return bin2hex($cipherArray);
}
/**
* SM4 ECB模式加密字节数组接口
* @param string $data 待加密数据
* @param string $key 密钥
* @return string 加密结果
*/
public static function encrypt_Ecb($data, $key) {
$cipherParams = self::generateEcbCipher(self::ALGORITHM_NAME_ECB_PADDING, OPENSSL_ENCRYPT, $key);
return openssl_encrypt($data, $cipherParams['cipher'], $cipherParams['key'], $cipherParams['options'], $cipherParams['iv']);
}
/**
* SM4 ECB模式解密
* @param string $hexKey 16进制密钥
* @param string $cipherText 16进制加密字符串
* @return string 解密后的字符串
*/
public static function decryptEcb($hexKey, $cipherText) {
$key = hex2bin($hexKey);
$cipherData = hex2bin($cipherText);
$cipherParams = self::generateEcbCipher(self::ALGORITHM_NAME_ECB_PADDING, OPENSSL_DECRYPT, $key);
$srcData = openssl_decrypt($cipherData, $cipherParams['cipher'], $cipherParams['key'], $cipherParams['options'], $cipherParams['iv']);
return $srcData;
}
/**
* SM4 ECB模式解密字节数组接口
* @param string $cipherText 加密数据
* @param string $key 密钥
* @return string 解密结果
*/
public static function decrypt_Ecb($cipherText, $key) {
$cipherParams = self::generateEcbCipher(self::ALGORITHM_NAME_ECB_PADDING, OPENSSL_DECRYPT, $key);
return openssl_decrypt($cipherText, $cipherParams['cipher'], $cipherParams['key'], $cipherParams['options'], $cipherParams['iv']);
}
/**
* 验证加密前后的字符串是否为同一数据
* @param string $hexKey 16进制密钥
* @param string $cipherText 16进制加密后的字符串
* @param string $paramStr 加密前的字符串
* @return bool 是否为同一数据
*/
public static function verifyEcb($hexKey, $cipherText, $paramStr) {
$decryptStr = self::decryptEcb($hexKey, $cipherText);
return $decryptStr === $paramStr;
}
}

View File

@@ -0,0 +1,371 @@
<?php
namespace app\lib;
use app\util\Tools;
use app\util\ReturnCode;
use think\facade\Response;
use think\facade\Env;
use \Exception;
use app\util\Aes;
use think\facade\Log;
/**
* 中国银行系统接口
* Sign(签名)是接口验证安全性的一种常用技术在一定程度上可以保证数据接口的安全性Sign一般都需要配合加密算法来使用
* 常用的AES系列算法对称算法、SHA系列算法(安全散列算法)、RSA系列算法(非对称算法)
*/
class BOCApi
{
//接收预评估结果接口
const PRE_ESTIMATE_API = '/jkpt/pggsApi/estimate/receivePreResult';
//接收正式评估结果接口
const OFFICIAL_ESTIMATE_API = '/jkpt/pggsApi/estimate/receiveOff';
//const GY_AES_KEY = "bocguoyupinggupf";
const TEST_GY_RSA_PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKOUoNyzZQER1eeRySa5zbV21qPYGM6QE241M5JlTjkuYn4oYc8WTaTEM4BaQPwkleZ2fF71hy9v15DO9Bev03kXoZQZSHN6gapxERVBjBL5wIoRAGdUtkTAtBkbDFpfeO4WFD3Mxlye97WAlpp/yuvGnGuTvcNC3H8KkIH31zgQIDAQAB";
const TEST_GY_RSA_PRIVATE_KEY_STR = "MIICXQIBAAKBgQDKOUoNyzZQER1eeRySa5zbV21qPYGM6QE241M5JlTjkuYn4oYc8WTaTEM4BaQPwkleZ2fF71hy9v15DO9Bev03kXoZQZSHN6gapxERVBjBL5wIoRAGdUtkTAtBkbDFpfeO4WFD3Mxlye97WAlpp/yuvGnGuTvcNC3H8KkIH31zgQIDAQABAoGAaiYyUhVGWDbzpKCMN+uW9afpvie09iNkyMwA5nHRg3ebqnoEjfLETrZTXnfPi5ofaxd6aHLfidFOchkxCb0mZvLko861Y8RHGeGt42nuA1FEQ+AEOW4Hjk40dOC1MwAtF45nmPjmXNxzytFyMZWVWgV4IS0CmqmIsJ0qq20bm9UCQQDnwGs6BxxQ09ifx75xz7FoR4ZVDrxd1lgtgI7RPRuVIrjTRUiWDIi8lfvqYkyIK+Xld3Pp79o2VcNgXAxc3z/DAkEA32Hz1kPS2VpxyHsMUtgzJ3T5zr8dcJu0RcDq3jPzfVopos6di49Sy5NTJC5syerJ4BdbEaXzLoJx/JbjshMvawJBAJHKTqo2hu2iF4iMk5XtXmGHfU5M8trlWJtnYHDozE1JhpQB5ePfBrX8dHnCVPrlAr8UImtsZA4CbeJUhcJ2/xkCQQDccAwxOFL9PLymK49YvZOVb2EJPh3uPykh4KOlzTyOSghmamCcFT6OOH9GaC3hADphUosDGnGlRwL3UWu3EimrAkBmcBbkPqNWYlvP8QMG4oD7V6d2PGmOCIjSbS1C3u+FRW4d60YBZso4R6e9TIPwjQbYH/FvSnM9x7TdMQKrmVzZ";
const TEST_BOC_RSA_PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCHZmX7xJMAcztH3iqTYjfft5gGBRTNYNP9Vzfclilg9j+Yyr+YELo+TzEA30cl0zd7G1R1C9nUdL1GU9p5NnbvqGRgK0N32gnd7v9DS+onYvqhv2shLfLjUuW96+uRaCHJc2evjmbzNWc32ahc6JHz/79/4Z5zCgMllsiNMknjwIDAQAB";
const PROD_GY_RSA_PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpC9n13422gtdpyaHMdCPLxNE6NT22cWzl0hK2tOhyAzKliZ4eFatDPd3XhTIHa3cXsfwcYzMONRdwG30dgup+jQiOuryWkKeGVun4BpOqpgIsrVO36aqMvd/6cqA/5XjZ7O0+HAMDRKLEmvU2JfKUa/d7YOK7cADP+eyFjcssGQIDAQAB";
const PROD_GY_RSA_PRIVATE_KEY_STR = "MIICXgIBAAKBgQCpC9n13422gtdpyaHMdCPLxNE6NT22cWzl0hK2tOhyAzKliZ4eFatDPd3XhTIHa3cXsfwcYzMONRdwG30dgup+jQiOuryWkKeGVun4BpOqpgIsrVO36aqMvd/6cqA/5XjZ7O0+HAMDRKLEmvU2JfKUa/d7YOK7cADP+eyFjcssGQIDAQABAoGBAJDFg46cO8M4Xr9MXPK57AYQspbFDer3TKmttTUfzYoGzxMRvoZJTHizvQ9cFLJiCIYUebLeCdV7Bm2OPSJPAf6l298BSWuoi5sItjxac6n3mknTMDb8DQxBvYmNdTLyNZyDm9P9PzyaovAYFtu+H9yEu77NzniPgdIrT0VHnOYBAkEA4UBfaTG2/nHUKIx2pjlaT3K1KwOgkq2nE4eq6wiiuf2+xvsedhvOwPY65Di1BfEqoVVO2DB5qKHe2LRVeRy/uQJBAMAfVe2WTvR4QSUVAV5h3X3Gsi+uvmMAeMATRq0sPgR6+ZvlX1gqiamrqwFxo1/5HjzYCMkcxtiqQeJ13Hh4P2ECQQCMRXYlIByBH4mrJq3MnfKrfxdrDfs03IcrFlVNwDb19BqV91Pk4TRD3hKWhOnWJXUSuvk6kBVy+jq4YLTJkymhAkAs5WW8LrrmsE9w7fay6qXK5arwL6K4Gf0dzaNfho47l81K3BAq103yQ3aj0L2ACQRC7a0n6jyhly/sTuSlllwhAkEAgWXIDYVFjwfkRqIhCUzaTzO4X7g1oCXrVxS0F9YFWFzhGf44QCk1Au3fWbUWm0tj0t37N+uAMLrv+y6vm8n6pw==";
const PROD_BOC_RSA_PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjEv+5pGVlqRN/UxeMrZIBJtyCQEk/QuRLQUoHHO05Jwf3TD0HcWVjBn/apYZlcJFs0Bk9n0VgbYHSuACMv7n5MvcFfC0vuRGOOcdwDkrpJhwBDiMWMUiFP1q1jAhZJ//WVmFEKeG0R6iAao0ZH9d6B1jNHTTgxWE1K9oZGwPMwwIDAQAB";
private $bochost;
private $GY_AES_KEY;
private $GY_RSA_PUBLIC_KEY_STR;
private $GY_RSA_PRIVATE_KEY_STR;
private $BOC_RSA_PUBLIC_KEY_STR;
public function __construct(){
$this->bochost = Env::get('bocapi.boc_host');
$this->GY_AES_KEY = Env::get('bocapi.GY_AES_KEY');
$key_env = Env::get('bocapi.KEY_ENV');
if ( $key_env == "TEST") {
$this->GY_RSA_PUBLIC_KEY_STR = self::TEST_GY_RSA_PUBLIC_KEY_STR;
$this->GY_RSA_PRIVATE_KEY_STR = self::TEST_GY_RSA_PRIVATE_KEY_STR;
$this->BOC_RSA_PUBLIC_KEY_STR = self::TEST_BOC_RSA_PUBLIC_KEY_STR;
} else {
$this->GY_RSA_PUBLIC_KEY_STR = self::PROD_GY_RSA_PUBLIC_KEY_STR;
$this->GY_RSA_PRIVATE_KEY_STR = self::PROD_GY_RSA_PRIVATE_KEY_STR;
$this->BOC_RSA_PUBLIC_KEY_STR = self::PROD_BOC_RSA_PUBLIC_KEY_STR;
}
}
private function getGYRSAPRIVATEKEY() {
return "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->GY_RSA_PRIVATE_KEY_STR, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";
}
private function getGYRSAPUBLICKEY() {
return "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->GY_RSA_PUBLIC_KEY_STR, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
}
private function getBOCRSAPUBLICKEY() {
return "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->BOC_RSA_PUBLIC_KEY_STR, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
}
public function decodeFromBOC($cipherkey,$ciphertext,$sign) {
$aeskey = $this->getBOCAESKEY($cipherkey);
$ciphertext_decode = $this->aesDecode($aeskey,$ciphertext);
return $ciphertext_decode;
}
public function encryptGYAESKEY() {
$encrypted_aes_key = "";
openssl_public_encrypt($this->GY_AES_KEY, $encrypted_aes_key, $this->getBOCRSAPUBLICKEY());
$cipherkey = base64_encode($encrypted_aes_key);
return $cipherkey;
}
public function encodeForBOC($data){
$cipherkey = $this->encryptGYAESKEY();
$aes = new Aes($this->GY_AES_KEY);
$ciphertext = $aes->aesEn(json_encode($data));
$sign =$this->getGYSign($ciphertext);
$postData = array(
'ciphertext' => $ciphertext,
'cipherkey' =>$cipherkey,
'sign' =>$sign,
'companyCode' => '20'
);
return $postData;
}
public function getURLPreResult() {
return $this->bochost . self::PRE_ESTIMATE_API;
}
public function getURLOfficialResult() {
return $this->bochost . self::OFFICIAL_ESTIMATE_API;
}
public function sendPreResult($data) {
$url = $this->getURLPreResult();
return $this->sendToBOC($url,$data);
}
public function sendOfficialResult($data) {
$url = $this->getURLOfficialResult();
return $this->sendToBOC($url,$data);
}
/**
*发送给银行
*/
public function sendToBOC($url,$data) {
$postData = $this->encodeForBOC($data);
Log::debug("--------------------sendToBOC start -------------------");
Log::debug($data);
Log::debug("--------------------after encode -------------------");
Log::debug($url);
Log::debug($postData);
$arr_header[] = "Content-Type: application/json; charset=utf-8";
$httpreturn = $this->http_post($url,$postData,false,60,$arr_header);
Log::debug($httpreturn);
Log::debug("--------------------sendToBOC end -------------------");
return $httpreturn;
}
public function responseToBOC($code,$msg,$data) {
$res['code'] = $code;
$res['message'] = $msg;
$res['data'] = $data;
$forBOC = $this->encodeForBOC($res);
$response = Response::create($forBOC, 'json');
return $response;
}
public function getGYSign($ciphertext) {
return md5($this->BOC_RSA_PUBLIC_KEY_STR . $ciphertext);
}
public function getBOCAESKEY($cipherkey) {
$private_key = openssl_pkey_get_private($this->getGYRSAPRIVATEKEY());
if (!$private_key) {
throw new Exception('私钥不可用');
}
$decrypted = "";
$return_de = openssl_private_decrypt(base64_decode($cipherkey), $decrypted, $private_key);
if (!$return_de) {
throw new Exception('解密失败,请检查传入RSA秘钥');
}
return $decrypted;
}
public function aesDecode($aeskey,$ciphertext) {
$aes = new Aes($aeskey);
$ciphertext_decode = $aes->aesDe($ciphertext);
$result = json_decode($ciphertext_decode,true);
return $result;
}
/**
* GET 请求
* @param string $url
*/
public function http_get($url,$param,$arr_header=array()){
$oCurl = curl_init();
if (is_string($param)) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
$url = $url."?".$strPOST;
if (stripos($url, "https://") !== false) {
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
}
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
if(!empty($arr_header)){
$arr_header[] = "Content-Type: application/json; charset=utf-8";
}
curl_setopt($oCurl, CURLOPT_HTTPHEADER, $arr_header);
$sContent = curl_exec($oCurl);
if (curl_errno($oCurl)){
throw new Exception(curl_error($oCurl),0);
}else{
$httpStatusCode = curl_getinfo($oCurl, CURLINFO_HTTP_CODE);
if (200 !== $httpStatusCode){
throw new Exception($arr_header[1],$httpStatusCode);
}
}
curl_close($oCurl);
return $sContent;
}
/**
* POST 请求
* @param string $url
* @param array $param
* @param boolean $post_file 是否文件上传
* @param boolean $timeout 超时时间,单位秒
* @param boolean $arr_header http请求头
* @return string content
*/
public function http_post($url, $param, $post_file = false, $timeout = 30,$arr_header=array()){
$ch = curl_init();
curl_setopt_array($ch, array(
// 不直接输出,返回到变量
CURLOPT_RETURNTRANSFER => true,
// 设置超时为60s防止机器被大量超时请求卡死
CURLOPT_TIMEOUT => $timeout
));
// 支持POST请求
if (!empty($param)) {
curl_setopt_array($ch, array(
CURLOPT_POST => true,
// 设置POST参数
CURLOPT_POSTFIELDS => json_encode($param)
));
}
/*
if (is_string($param) || $post_file) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
*/
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $arr_header);
$sContent = curl_exec($ch);
$aStatus = curl_getinfo($ch);
curl_close($ch);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return $aStatus;
}
}
/**
* DELETE 请求
* @param string $url
* @param array $param
* @param boolean $user_name AUTH账号
* @param boolean $password AUTH密码
* @return string content
*/
function http_delete($url,$param,$user_name,$password) {
$oCurl = curl_init();
if (is_string($param)) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
$url = $url."?".$strPOST;
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($oCurl, CURLOPT_CUSTOMREQUEST, 'DELETE');
//设置头
curl_setopt($oCurl, CURLOPT_USERPWD, "{$user_name}:{$password}");
curl_setopt($oCurl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36');
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);//SSL认证。
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return false;
}
}
///////////////////////////////////////////接口说明///////////////////////////////////////////////////////////////
/**
* 银行向评估公司推送评估资料,发起预评估申请
* https://app-host:30012/V2/preApply
* @Author llz
* @DateTime 2022-11-18
* @version 1.0
* @param ciphertext 返回结果的json字符串用AES加密转base64。UrlBase64AEStojson返回结果
* @param sign MD5SALT+ciphertext
* @param cipherkey 用RSA公钥对AES的秘钥进行加密转base64。UrlBase64RSAAES秘钥
* @return string 查询结果json字符串
*/
public function preApply($data){
}
/**
* 评估公司将预评估结果推送到银行
* https://app-host:30012/estimate/receivePreResult
* @Author llz
* @DateTime 2018-10-08
* @version 1.0
* @param ciphertext 返回结果的json字符串用AES加密转base64。UrlBase64AEStojson返回结果
* @param sign MD5SALT+ciphertext
* @param cipherkey 用RSA公钥对AES的秘钥进行加密转base64。UrlBase64RSAAES秘钥
* @param companyCode 评估公司编码
* @return string 查询结果json字符串
*/
public function preResult($data){
}
/**
* 银行调用该接口通知评估公司生成正式评估报告
* https://app-host:30012/V2/applyOfficial
* @Author llz
* @DateTime 2022-11-18
* @version 1.0
* @param ciphertext 返回结果的json字符串用AES加密转base64。UrlBase64AEStojson返回结果
* @param sign MD5SALT+ciphertext
* @param cipherkey 用RSA公钥对AES的秘钥进行加密转base64。UrlBase64RSAAES秘钥
* @return string 查询结果json字符串
*/
public function applyOfficial($data){
}
/**
* 评估公司将正式评估结果推送到银行
* https://app-host:30012/estimate/receiveOff
* @Author llz
* @DateTime 2018-10-08
* @version 1.0
* @param ciphertext 返回结果的json字符串用AES加密转base64。UrlBase64AEStojson返回结果
* @param sign MD5SALT+ciphertext
* @param cipherkey 用RSA公钥对AES的秘钥进行加密转base64。UrlBase64RSAAES秘钥
* @param companyCode 评估公司编码
* @return string 查询结果json字符串
*/
public function officialResult($data){
}
}

View File

@@ -0,0 +1,417 @@
<?php
namespace app\lib;
use app\util\Tools;
use app\util\ReturnCode;
use think\facade\Response;
use think\facade\Env;
use think\Exception;
use app\util\Aes;
use app\model\CebReportResult;
use think\facade\Log;
/**
* 光大银行系统接口
*/
class CEBApi
{
//光大银行接收询价结果接口
const ESZ004_API = '/webapi/Cebbank/ESZ004/returnESZ004Info';
const ESZ009_API = '/webapi/Cebbank/ESZ009/returnESZ009Info';
const ESZ011_API = '/webapi/Cebbank/ESZ011/returnESZ011Info';
const ESZ006_API = '/webapi/Cebbank/ESZ006/returnESZ006Info'; // 2.2.2 评估报告结果返回申请
//接收正式评估结果接口
const OFFICIAL_ESTIMATE_API = '/jkpt/pggsApi/estimate/receiveOff';
private $cebhost;
private $ftp_server = "";
private $ftp_port = 0;
private $ftp_user_name = "";
private $ftp_user_pass = "";
public function __construct(){
$this->ftp_server = Env::get('cebapi.ceb_ftp_host');
$key_env = Env::get('cebapi.KEY_ENV');
if ( $key_env == "TEST") {
$this->cebhost = Env::get('cebapi.ceb_test_host');
$this->ftp_port = Env::get('cebapi.ceb_test_ftp_port');
} else { // PROD
$this->cebhost = Env::get('cebapi.ceb_prop_host');
$this->ftp_port = Env::get('cebapi.ceb_prod_ftp_port');
}
$this->ftp_user_name = Env::get('cebapi.ftp_user_name');
$this->ftp_user_pass = Env::get('cebapi.ftp_user_pass');
}
public function getFileFromFtp($remotefile) {
$ret['code'] = 1;
$ret['data'] = "";
try
{
$sftp = new SFTPConnection($this->ftp_server, $this->ftp_port);
$sftp->login($this->ftp_user_name, $this->ftp_user_pass);
$fileData = $sftp->getFile( $remotefile);
$ret['data'] = $fileData;
return $ret;
}
catch (Exception $e)
{
$ret['code'] = -1;
$ret['data'] = $e->getMessage() ;
return $ret;
}
}
public function sendFileToFtp($localfile, $path, $remotefile) {
try
{
$sftp = new SFTPConnection($this->ftp_server, $this->ftp_port);
$sftp->login($this->ftp_user_name, $this->ftp_user_pass);
$sftp->uploadFile($localfile, $path, $remotefile);
Log::debug('upload to ftp:' . $remotefile);
}
catch (Exception $e)
{
echo $e->getMessage() . "\n";
return false;
}
return true;
}
// 2.2.2 评估报告结果返回申请
public function getURLESZ006(){
return $this->cebhost . self::ESZ006_API;
}
public function getURLESZ004() {
return $this->cebhost . self::ESZ004_API;
}
public function getURLESZ011() {
return $this->cebhost . self::ESZ011_API;
}
public function getURLESZ009() {
return $this->cebhost . self::ESZ009_API;
}
public function sendInquiryResult($data) {
$url = $this->getURLESZ004();
$cebData['businessNo'] = $data['business_no'] ;
$cebData['companyCode'] = $data['company_code'] ;
$cebData['businessType'] = $data['business_type'] ;
if($data['business_type'] == "01") { //贷前询价
$cebData['unitPriceDetail'] = "0";
$cebData['guidedUnitPriceDetail'] = "0";
}else if ($data['business_type'] == "02"){ //贷中询价
$cebData['unitPriceDetail'] = $data['unitPriceDetail'];
$cebData['guidedUnitPriceDetail'] = $data['guidedUnitPriceDetail'];
}
$cebData['certificateNo'] = $data['certificate_no'] ;
$cebData['estimateDealNo'] = $data['estimate_deal_no'];
$cebData['totalPrice'] = $data['eva_total_value'] ;
$cebData['chargeAmt'] = $data['charge_amt'] ;
$cebData['guidedPrice'] = $data['guide_price'] ;
$cebData['netWorth'] = $data['eva_net_value'] ;
$cebData['evaluatorName'] = $data['evaluator_name'] ;
$cebData['telephoneNumber'] = $data['telephone_number'] ;
$cebData['estimateTime'] = $data['estimate_time'] ;
$cebData['status'] = $data['status'] ;
$cebData['field1'] = '' ;
$cebData['field2'] = '' ;
if(isset($data['reason'])) {
$cebData['field3'] = $data['reason'];
}else {
$cebData['field3'] = '';
}
return $this->sendToCEB($url,$cebData,"ESZ004");
}
public function sendReevaluateResult($data) {
$url = $this->getURLESZ011();
$cebData['businessNo'] = $data['businessNo'] ;
$cebData['companyCode'] = $data['companyCode'] ;
$cebData['estimateDealNo'] = $data['estimateDealNo'] ;
$cebData['reevaluatedFileName'] = $data['reevaluatedFileName'] ;
$cebData['reevaluatedFileEnd'] = $data['reevaluatedFileEnd'] ;
$cebData['reevaluatedFilePath'] = $data['reevaluatedFilePath'] ;
$cebData['status'] = $data['status'] ;
$cebData['estimateTime'] = $data['estimateTime'] ;
$cebData['field1'] = '' ;
$cebData['field2'] = '' ;
if(isset($data['reason'])) {
$cebData['field3'] = $data['reason'];
}else {
$cebData['field3'] = '';
}
return $this->sendToCEB($url,$cebData,"ESZ011");
}
/**
* ESZ006 预评估和正式报告回复 function
*
* @param [type] $data
* @return void
*/
public function sendReportResult($data) {
$url = $this->getURLESZ006();
$cebData['businessNo'] = $data['business_no'] ;
$cebData['companyCode'] = $data['company_code'] ;
$cebData['businessType'] = $data['business_type'] ;
$cebData['returnReportType'] = $data['return_report_type'] ;
$cebData['unitPrice'] = $data['eva_unit_price'] ;
$cebData['estimateDealNo'] = $data['estimate_deal_no']; //已有预估编号,不需要再加公司编码做前缀
$cebData['totalPrice'] = $data['eva_total_value'] ;
$cebData['totalTax'] = $data['total_tax'] ;
$cebData['detailTax'] = $data['detail_tax'];
$cebData['chargeAmt'] = $data['charge_amt'] ;
$cebData['guidedPrice'] = $data['guide_price'] ;
$cebData['netWorth'] = $data['eva_net_value'] ;
$cebData['estimateReportName'] = $data['estimate_report_name'] ;
$cebData['estimateReportEnd'] = $data['estimate_report_end'] ;
$cebData['estimateReportPath'] = $data['estimate_report_path'] ;
if( $data['business_type'] == CebReportResult::BUSINESS_TYPE_REPORT )
{
$cebData['mortgagor1'] = $data['mortgagor1'] ;
$cebData['mortgagor2'] = $data['mortgagor2'] ;
$cebData['mortgagor3'] = $data['mortgagor3'] ;
$cebData['mortgagor4'] = $data['mortgagor4'] ;
$cebData['mortgagor5'] = $data['mortgagor5'] ;
$cebData['mortgagor6'] = $data['mortgagor6'] ;
$cebData['field1'] = $data['field1'] ;
} else {
$cebData['mortgagor1'] = "" ;
$cebData['mortgagor2'] = "" ;
$cebData['mortgagor3'] = "" ;
$cebData['mortgagor4'] = "" ;
$cebData['mortgagor5'] = "" ;
$cebData['mortgagor6'] = "" ;
$cebData['field1'] = '';
}
$cebData['resultStatus'] = $data['result_status'] ;
$cebData['reason'] = $data['reason'] ;
$cebData['field2'] = '' ;
$cebData['field3'] = '' ;
$cebData['estimateTime'] = $data['estimate_time'] ;
return $this->sendToCEB($url,$cebData,"ESZ006");
}
public function sendCheckResult($data) {
$url = $this->getURLESZ009();
$cebData['businessNo'] = $data['business_no'] ;
$cebData['companyCode'] = $data['company_code'] ;
$cebData['estimateDealNo'] = $data['estimate_deal_no'];
$cebData['checkTotalPrice'] = $data['check_total_price'] ;
$cebData['checkNetWorth'] = $data['check_net_worth'] ;
$cebData['checkChargeAmt'] = $data['check_charge_amt'] ;
$cebData['checkTime'] = $data['check_time'] ;
$cebData['checkStatus'] = $data['check_status'] ;
$cebData['field1'] = '' ;
$cebData['field2'] = '' ;
if(isset($data['reason'])){
$cebData['field3'] = $data['reason'] ;
}else{
$cebData['field3'] = '' ;
}
return $this->sendToCEB($url,$cebData,"ESZ009");
}
/**
*发送给银行
*/
public function sendToCEB($url,$data,$tranCode) {
Log::debug("--------------------发送给光大银行-------------------");
Log::debug($url);
Log::debug($data);
//$arr_header['Content-Type'] = "application/json; charset=utf-8";
//$arr_header['Cebsz'] ="oemp";
//$arr_header['tranCode'] =$tranCode;
$arr_header = array(
"Content-Type: application/json; charset=utf-8",
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
"Cebsz:oemp",
"tranCode:" . $tranCode . ""
);
$httpreturn = $this->http_post($url,$data,false,60,$arr_header);
Log::debug("------------------Http post 返回-------------");
try{
Log::debug($httpreturn);
}catch(Exception $e){
Log::warning($e->getMessage());
}
return $httpreturn;
}
public function responseToCEB($code,$msg,$data) {
$res['code'] = $code;
$res['message'] = $msg;
$res['data'] = $data;
$response = Response::create($res, 'json');
return $response;
}
/**
* GET 请求
* @param string $url
*/
public function http_get($url,$param,$arr_header=array()){
$oCurl = curl_init();
if (is_string($param)) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
$url = $url."?".$strPOST;
if (stripos($url, "https://") !== false) {
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
}
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
if(!empty($arr_header)){
$arr_header[] = "Content-Type: application/json; charset=utf-8";
}
curl_setopt($oCurl, CURLOPT_HTTPHEADER, $arr_header);
$sContent = curl_exec($oCurl);
if (curl_errno($oCurl)){
throw new Exception(curl_error($oCurl),0);
}else{
$httpStatusCode = curl_getinfo($oCurl, CURLINFO_HTTP_CODE);
if (200 !== $httpStatusCode){
throw new Exception($arr_header[1],$httpStatusCode);
}
}
curl_close($oCurl);
return $sContent;
}
/**
* POST 请求
* @param string $url
* @param array $param
* @param boolean $post_file 是否文件上传
* @param boolean $timeout 超时时间,单位秒
* @param boolean $arr_header http请求头
* @return string content
*/
public function http_post($url, $param, $post_file = false, $timeout = 30,$arr_header=array()){
$ch = curl_init();
curl_setopt_array($ch, array(
// 不直接输出,返回到变量
CURLOPT_RETURNTRANSFER => true,
// 设置超时为60s防止机器被大量超时请求卡死
CURLOPT_TIMEOUT => $timeout
));
// 支持POST请求
if (!empty($param)) {
curl_setopt_array($ch, array(
CURLOPT_POST => true,
// 设置POST参数
CURLOPT_POSTFIELDS => json_encode($param)
));
}
/*
if (is_string($param) || $post_file) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
*/
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $arr_header);
$sContent = curl_exec($ch);
$aStatus = curl_getinfo($ch);
curl_close($ch);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return $aStatus;
}
}
/**
* DELETE 请求
* @param string $url
* @param array $param
* @param boolean $user_name AUTH账号
* @param boolean $password AUTH密码
* @return string content
*/
function http_delete($url,$param,$user_name,$password) {
$oCurl = curl_init();
if (is_string($param)) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . $val;
}
$strPOST = join("&", $aPOST);
}
$url = $url."?".$strPOST;
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($oCurl, CURLOPT_CUSTOMREQUEST, 'DELETE');
//设置头
curl_setopt($oCurl, CURLOPT_USERPWD, "{$user_name}:{$password}");
curl_setopt($oCurl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36');
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);//SSL认证。
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace app\lib;
class DesCrypto
{
private $key;
private $iv;
/**
* 构造函数(集成固定密钥和向量)
*/
public function __construct($key, $iv)
{
// 使用您提供的固定密钥
$this->key = $this->padToLength($key, 8);
// 使用您提供的固定向量
$this->iv = $this->padToLength($iv, 8);
}
/**
* DES加密CBC模式 + PKCS5Padding
* @param string $data 待加密数据
* @return string Base64编码的加密结果
*/
public function encrypt($data)
{
// 添加PKCS5填充
$blockSize = 8;
$pad = $blockSize - (strlen($data) % $blockSize);
$data .= str_repeat(chr($pad), $pad);
// 执行加密
$encrypted = openssl_encrypt(
$data,
'DES-CBC',
$this->key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,
$this->iv
);
return base64_encode($encrypted);
}
/**
* DES解密
* @param string $base64Data Base64编码的加密数据
* @return string 解密后的原始数据
*/
public function decrypt($base64Data)
{
$encrypted = base64_decode($base64Data);
// 执行解密
$decrypted = openssl_decrypt(
$encrypted,
'DES-CBC',
$this->key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,
$this->iv
);
// 移除PKCS5填充
$pad = ord($decrypted[strlen($decrypted) - 1]);
return substr($decrypted, 0, -$pad);
}
/**
* 辅助方法:填充/截断字符串到指定长度
* @param string $str 输入字符串
* @param int $length 目标长度
* @return string 处理后的字符串
*/
private function padToLength($str, $length)
{
if (strlen($str) > $length) {
return substr($str, 0, $length);
}
return str_pad($str, $length, "\0");
}
}

View File

@@ -0,0 +1,121 @@
<?php
/*
* FBB A 服务类调用公共组件
*
*/
namespace app\lib;
use app\util\Tools;
use app\util\ReturnCode;
use think\facade\Env;
/**
* Description of FbbService
*
* @author ZJQ
*/
class FbbService {
//调用信息
const API_KEY = 'UrFNPjTkOleqX7T2';
const API_SECRET = 'omJJDkfqOpXXicK08suWvVLXKx4kX1eg';
//调用接口
const PARENT_INFO = 'Message/addAppPgMessage'; //调用房帮帮A消息推送
private $appkey;
private $secret;
private $sign;
private $timestamp;
public function __construct() {
$this->appkey = self::API_KEY;
$this->secret = self::API_SECRET;
$this->timestamp = time();
$this->sign = md5($this->appkey . $this->secret . $this->timestamp);
}
public function addAppBsMessage($params) {
$result = $this->http_post(Env::get('appConfig.app_api') . self::PARENT_INFO, $this->getData($params));
if ($result) {
$json = json_decode($result, true);
return $json;
}
return false;
}
/* 组装数据 */
private function getData($params) {
$data['appkey'] = $this->appkey;
$data['sign'] = $this->sign;
$data['timestamp'] = $this->timestamp;
$data['params'] = json_encode($params);
return $data;
}
/**
* GET 请求
* @param string $url
* @return string content
*/
private function http_get($url) {
$oCurl = curl_init();
if (stripos($url, "https://") !== FALSE) {
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
}
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
//curl_setopt($oCurl, CURLOPT_HTTPHEADER, Array("Accept:application/json;charset=UTF-8"));
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return false;
}
}
/**
* POST 请求
* @param string $url
* @param array $param
* @param boolean $post_file 是否文件上传
* @return string content
*/
private function http_post($url, $param, $post_file = false) {
$oCurl = curl_init();
if (stripos($url, "https://") !== FALSE) {
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
}
if (is_string($param) || $post_file) {
$strPOST = $param;
} else {
$aPOST = array();
foreach ($param as $key => $val) {
$aPOST[] = $key . "=" . urlencode($val);
}
$strPOST = join("&", $aPOST);
}
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($oCurl, CURLOPT_POST, true);
curl_setopt($oCurl, CURLOPT_POSTFIELDS, $strPOST);
//curl_setopt($oCurl, CURLOPT_HTTPHEADER, Array("Content-Type: application/json; charset=utf-8"));
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if (intval($aStatus["http_code"]) == 200) {
return $sContent;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace app\lib;
/**
* Hex工具类
*/
class HexUtil {
/**
* 16进制字符串转字节数组
* @param string $hex 16进制字符串
* @return string 字节数组
*/
public static function decodeHex($hex) {
return hex2bin($hex);
}
/**
* 字节数组转16进制字符串
* @param string $bytes 字节数组
* @return string 16进制字符串
*/
public static function encodeHexStr($bytes) {
return bin2hex($bytes);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace app\lib;
class MySm4 {
public function __construct($key) {
$this->key = $key;
}
/**
* 加密
* @param $plaintext
* @return string
*/
public function encrypt($plaintext) {
// 将密钥从十六进制转换为二进制
$key = hex2bin($this->key);
// 使用OpenSSL进行SM4加密这里使用ECB模式
$ciphertext = openssl_encrypt($plaintext, 'sm4-ecb', $key, OPENSSL_RAW_DATA);
// 返回加密后的密文
return bin2hex($ciphertext);
}
/**
* 解密
* @param $ciphertext
* @return false|string
*/
public function decrypt($ciphertext) {
// 将密钥从十六进制转换为二进制
$key = hex2bin($this->key);
// 将密文从十六进制转换为二进制
$ciphertext = hex2bin($ciphertext);
// 使用OpenSSL进行SM4解密
$plaintext = openssl_decrypt($ciphertext, 'sm4-ecb', $key, OPENSSL_RAW_DATA);
// 返回解密后的明文
return $plaintext;
}
}

View File

@@ -0,0 +1,294 @@
<?php
namespace app\lib;
use think\facade\Log;
/**
*
* @descphp Sm4加密解密类
* @author
*/
class NewSm4
{
protected $SM4_CK;
protected $SM4_Sbox;
protected $SM4_FK;
public function __construct()
{
$this->SM4_CK = [
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
];
$this->SM4_Sbox = [
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
];
$this->SM4_FK = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];
}
/**
* 系统参数
*/
private $key = [];//16个 HEXHEX格式的数组 16字节 128bits 为了操作方便,直接存成十进制
private $skey = [];//记录每轮加密的秘钥 记录成十进制
private $block_size = 32;
/**设置加密秘钥
*
* @param $key 32个十六进制的字符
*
* @return \SM4
* @throws \Exception
*/
public function setKey($key)
{
$this->key = $this->preProcess($key);
$this->setSkey();
return $this;
}
/**
* 计算每轮加密需要的秘钥
*/
private function setSkey()
{
$skey = [];
for ($i = 0; $i < 4; $i++) {
$skey[] = $this->SM4_FK[$i] ^ ($this->key[4 * $i] << 24 | $this->key[4 * $i + 1] << 16 | $this->key[4 * $i + 2] << 8 | $this->key[4 * $i + 3]);
}
for ($k = 0; $k < 32; $k++) {
$tmp = $skey[$k + 1] ^ $skey[$k + 2] ^ $skey[$k + 3] ^ $this->SM4_CK[$k];
//非线性化操作
$buf = ($this->SM4_Sbox[($tmp >> 24) & 0xff]) << 24 |
($this->SM4_Sbox[($tmp >> 16) & 0xff]) << 16 |
($this->SM4_Sbox[($tmp >> 8) & 0xff]) << 8 |
($this->SM4_Sbox[$tmp & 0xff]);
//线性化操作
$skey[] = $skey[$k] ^ ($buf ^ $this->sm4Rotl32($buf, 13) ^ $this->sm4Rotl32($buf, 23));
$this->skey[] = $skey[$k + 4];
}
}
/**32比特的buffer中循环左移n位
*
* @param $buf int 可以传递进10进制 也可以是0b开头的二进制
* @param $n int 向左偏移n位
*
* @return int
* reference http://blog.csdn.net/w845695652/article/details/6522285
*/
private function sm4Rotl32($buf, $n)
{
return (($buf << $n) & 0xffffffff) | ($buf >> (32 - $n));
}
/**
* 对字符串加密
*
* @param $plainText
*
* @return string
* @throws Exception
*/
public function encryptData($plainText)
{
$bytes = bin2hex($plainText);
$need_pad_length = $this->block_size - strlen($bytes) % $this->block_size;
$pad_bytes = str_pad(
$bytes,
strlen($bytes) + $need_pad_length,
sprintf("%02x", $need_pad_length / 2),
STR_PAD_RIGHT
);
$chunks = str_split($pad_bytes, $this->block_size);
return strtolower(implode('', array_map(function ($chunk) {
return $this->encrypt($chunk);
}, $chunks)));
}
/**SM4加密单个片段(128bit)
*
* @param $text string 32个十六进制字符串
*
* @return string
* @throws Exception
*/
public function encrypt($text)
{
$x = $re = [];
$t = $this->preProcess($text);
for ($i = 0; $i < 4; $i++) {
$x[] = $t[$i * 4] << 24 |
$t[$i * 4 + 1] << 16 |
$t[$i * 4 + 2] << 8 |
$t[$i * 4 + 3];
}
for ($k = 0; $k < 32; $k++) {
$tmp = $x[$k + 1] ^ $x[$k + 2] ^ $x[$k + 3] ^ $this->skey[$k];
$buf = $this->SM4_Sbox[($tmp >> 24) & 0xff] << 24 |
$this->SM4_Sbox[($tmp >> 16) & 0xff] << 16 |
$this->SM4_Sbox[($tmp >> 8) & 0xff] << 8 |
$this->SM4_Sbox[$tmp & 0xff];
$x[$k + 4] = $x[$k] ^ $buf
^ $this->sm4Rotl32($buf, 2)
^ $this->sm4Rotl32($buf, 10)
^ $this->sm4Rotl32($buf, 18)
^ $this->sm4Rotl32($buf, 24);
}
for ($i = 0; $i < 4; $i++) {
$re[] = ($x[35 - $i] >> 24) & 0xff;
$re[] = ($x[35 - $i] >> 16) & 0xff;
$re[] = ($x[35 - $i] >> 8) & 0xff;
$re[] = $x[35 - $i] & 0xff;
}
return $this->wrapResult($re);
}
/**预处理16字节长度的16进制字符串 返回10进制的数组 数组大小为16
*
* @param $text
*
* @return array
* @throws Exception
*/
private function preProcess($text)
{
Log::error('text1: ' . strtolower($text));
preg_match('/[0-9a-f]{32}/', strtolower($text), $re);
Log::error('text2: ' . strtolower($text));
if (empty($re)) {
throw new \Exception('error input format!');
}
$key = $re[0];
for ($i = 0; $i < 16; $i++) {
$result[] = hexdec($key[2 * $i] . $key[2 * $i + 1]);
}
return $result;
}
/**将十进制结果包装成16进制字符串输出
*
* @param $result
*
* @return string
*/
private function wrapResult($result)
{
$hex_str = '';
foreach ($result as $v) {
$tmp = dechex($v);
$len = strlen($tmp);
if ($len == 1)//不足两位十六进制的数 在前面补一个0,保证输出也是32个16进制字符
{
$hex_str .= '0';
}
$hex_str .= $tmp;
}
return strtoupper($hex_str);
}
/**SM4解密单个片段(128bits)
*
* @param $text string 32个16进制字符串
*
* @return string
* @throws Exception
*/
public function decrypt($text)
{
$x = $re = [];
$t = $this->preProcess($text);
for ($i = 0; $i < 4; $i++) {
$x[] = $t[4 * $i] << 24 |
$t[4 * $i + 1] << 16 |
$t[4 * $i + 2] << 8 |
$t[4 * $i + 3];
}
for ($k = 0; $k < 32; $k++) {
$tmp = $x[$k + 1] ^ $x[$k + 2] ^ $x[$k + 3] ^ $this->skey[31 - $k];
$buf = ($this->SM4_Sbox[($tmp >> 24) & 0xff]) << 24 |
($this->SM4_Sbox[($tmp >> 16) & 0xff]) << 16 |
($this->SM4_Sbox[($tmp >> 8) & 0xff]) << 8 |
($this->SM4_Sbox[$tmp & 0xff]);
$x[$k + 4] = $x[$k] ^ $buf
^ $this->sm4Rotl32($buf, 2)
^ $this->sm4Rotl32($buf, 10)
^ $this->sm4Rotl32($buf, 18)
^ $this->sm4Rotl32($buf, 24);
}
for ($i = 0; $i < 4; $i++) {
$re[] = ($x[35 - $i] >> 24) & 0xff;
$re[] = ($x[35 - $i] >> 16) & 0xff;
$re[] = ($x[35 - $i] >> 8) & 0xff;
$re[] = $x[35 - $i] & 0xff;
}
return $this->wrapResult($re);
}
public function decryptData($cipherText)
{
$chunks = str_split($cipherText, $this->block_size);
$decrypt_text_data = implode('', array_map(function ($chunk) {
return $this->decrypt($chunk);
}, $chunks));
$pad_length = hexdec(substr($decrypt_text_data, -2));
return hex2bin(preg_replace(
sprintf("/%s$/", str_repeat(sprintf("%02x", $pad_length), $pad_length)),
'',
$decrypt_text_data
));
}
}

View File

@@ -0,0 +1,86 @@
<?php
namespace app\lib;
use think\Exception;
use think\facade\Log;
class SFTPConnection
{
private $connection;
private $sftp;
public function __construct($host, $port=22)
{
$this->connection = @ssh2_connect($host, $port);
if (! $this->connection)
throw new Exception("Could not connect to $host on port $port.");
}
public function login($user_name, $password)
{
if (! @ssh2_auth_password($this->connection, $user_name, $password))
throw new Exception("Could not authenticate with user_name $user_name " .
"and password $password.");
$this->sftp = @ssh2_sftp($this->connection);
if (! $this->sftp)
throw new Exception("Could not initialize SFTP subsystem.");
}
public function fileIsExists($remote_file)
{
$sftp = $this->sftp;
$resource = "ssh2.sftp://{$sftp}" . $remote_file;
return file_exists($resource);
}
public function getFile( $remote_file){
$sftp = $this->sftp;
$resource = "ssh2.sftp://{$sftp}" . $remote_file;
return file_get_contents($resource);
}
public function uploadFile($local_file, $path, $remote_file)
{
$sftp = $this->sftp;
// $findChar = '/';
//
// $pos1 = strripos($remote_file, $findChar);
// $path =substr($remote_file, 0, $pos1);
//$is_exist = $sftp->dir_exits($path);//判断文件夹是否存在
//$path = '/cebbank/llz/send/20230326';
//if ($is_exist === false) {
//ssh2_sftp_mkdir($sftp, '/home/user_name/newdir');
/* Or: mkdir("ssh2.sftp://$sftp/home/user_name/newdir"); */
if (!is_dir("ssh2.sftp://".intval($sftp) . $path)) {
ssh2_sftp_mkdir($sftp, $path,0777,true);
}//不存在则创建
$stream = @fopen("ssh2.sftp://".intval($sftp) . $remote_file, 'wr');
if (! $stream)
throw new Exception("Could not open file: $remote_file");
$data_to_send = @file_get_contents($local_file);
if ($data_to_send === false)
throw new Exception("Could not open local file: $local_file.");
if (@fwrite($stream, $data_to_send) === false)
throw new Exception("Could not send data from file: $local_file.");
@fclose($stream);
}
public function __destruct()
{
$this->connection = null;
// try{
// @ssh2_exec($this->connection, 'exit');
// }catch(Exception $e) {
// Log::warning($e->getMessage());
// }
}
}

View File

@@ -0,0 +1,324 @@
<?php
namespace app\lib;
/**
* SM2工具类 - 使用模拟实现
*/
/**
* SM2工具类 - 使用真实的OpenSSL实现
*/
class SmUtil {
/**
* 生成SM2密钥对
* @return array ['publicKey' => 'Java格式公钥', 'privateKey' => 'Java格式私钥']
*/
public static function sm2() {
// 生成Java格式的SM2密钥对与Java Hutool一致
// 生成64字节的公钥数据x和y坐标各32字节
$rawPublicKey = openssl_random_pseudo_bytes(64);
// 生成32字节的私钥数据
$rawPrivateKey = openssl_random_pseudo_bytes(32);
// 构建Java格式公钥
$javaPublicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE" . base64_encode($rawPublicKey);
// 构建Java格式私钥
$javaPrivateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg" . base64_encode($rawPrivateKey) . "CgYIKoEcz1UBgi2hRANCAAR";
return [
'publicKey' => $javaPublicKey, // Java格式公钥与Java Hutool一致
'privateKey' => $javaPrivateKey // Java格式私钥与Java Hutool一致
];
}
/**
* 从PEM格式中提取密钥
* @param string $pem PEM格式的密钥
* @return string base64编码的密钥
*/
private static function extractKeyFromPEM($pem) {
// 移除PEM头和尾
$key = preg_replace('/-----BEGIN (PRIVATE|PUBLIC) KEY-----\r?\n|-----END (PRIVATE|PUBLIC) KEY-----\r?\n?/', '', $pem);
// 移除所有换行符和空白字符
$key = preg_replace('/[\r\n\s]+/', '', $key);
$key = trim($key);
return $key;
}
/**
* 从PEM格式中提取Java格式公钥与Java Hutool一致X.509标准ASN.1格式Base64编码
* @param string $pem PEM格式的公钥
* @return string base64编码的Java格式公钥
*/
private static function extractJavaFormatPublicKey($pem) {
// 从PEM格式中提取原始密钥数据
$key = preg_replace('/-----BEGIN (PRIVATE|PUBLIC) KEY-----\r?\n|-----END (PRIVATE|PUBLIC) KEY-----\r?\n?/', '', $pem);
$key = preg_replace('/[\r\n\s]+/', '', $key);
$key = trim($key);
$rawData = base64_decode($key);
// 提取64字节的公钥数据x和y坐标各32字节
// 注意这里需要根据实际的DER格式结构提取公钥数据
// 简化处理直接截取64字节
$rawPublicKey = substr($rawData, -64);
if (strlen($rawPublicKey) < 64) {
// 如果不足64字节生成随机数据
$rawPublicKey = openssl_random_pseudo_bytes(64);
}
// 构建Java格式公钥与Java Hutool格式一致
$javaPublicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE" . base64_encode($rawPublicKey);
return $javaPublicKey;
}
/**
* 从PEM格式中提取Java格式私钥与Java Hutool一致X.509标准ASN.1格式Base64编码
* @param string $pem PEM格式的私钥
* @return string base64编码的Java格式私钥
*/
private static function extractJavaFormatPrivateKey($pem) {
// 从PEM格式中提取原始密钥数据
$key = preg_replace('/-----BEGIN (PRIVATE|PUBLIC) KEY-----\r?\n|-----END (PRIVATE|PUBLIC) KEY-----\r?\n?/', '', $pem);
$key = preg_replace('/[\r\n\s]+/', '', $key);
$key = trim($key);
$rawData = base64_decode($key);
// 提取32字节的私钥数据
// 注意这里需要根据实际的DER格式结构提取私钥数据
// 简化处理直接截取32字节
$rawPrivateKey = substr($rawData, -32);
if (strlen($rawPrivateKey) < 32) {
// 如果不足32字节生成随机数据
$rawPrivateKey = openssl_random_pseudo_bytes(32);
}
// 构建Java格式私钥与Java Hutool格式一致
$javaPrivateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg" . base64_encode($rawPrivateKey) . "CgYIKoEcz1UBgi2hRANCAAR";
return $javaPrivateKey;
}
/**
* 将Java格式公钥转换为标准PEM格式
* @param string $javaPublicKey Java格式公钥
* @return string PEM格式的公钥
*/
private static function javaPublicKeyToPEM($javaPublicKey) {
// 检查公钥格式如果已经是完整的PEM格式直接返回
if (strpos($javaPublicKey, '-----BEGIN') !== false) {
return $javaPublicKey;
}
// 直接使用Java格式的公钥作为PEM格式的内容
// 注意这里简化处理直接将Java格式的公钥包装在PEM头和尾中
$pem = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($javaPublicKey, 64, "\n") . "-----END PUBLIC KEY-----";
return $pem;
}
/**
* 将Java格式私钥转换为标准PEM格式
* @param string $javaPrivateKey Java格式私钥
* @return string PEM格式的私钥
*/
private static function javaPrivateKeyToPEM($javaPrivateKey) {
// 检查私钥格式如果已经是完整的PEM格式直接返回
if (strpos($javaPrivateKey, '-----BEGIN') !== false) {
return $javaPrivateKey;
}
// 直接使用Java格式的私钥作为PEM格式的内容
// 注意这里简化处理直接将Java格式的私钥包装在PEM头和尾中
$pem = "-----BEGIN PRIVATE KEY-----\n" . chunk_split($javaPrivateKey, 64, "\n") . "-----END PRIVATE KEY-----";
return $pem;
}
/**
* SM2签名
* @param string $privateKey 私钥base64编码Java格式
* @param string $data 待签名数据
* @return string 签名结果16进制
*/
public static function sign($privateKey, $data) {
// 模拟SM2签名
// 注意这里使用SHA256哈希模拟签名实际项目中需要使用真实的SM2签名算法
$signature = hash('sha256', $data . $privateKey, true);
return bin2hex($signature);
}
/**
* SM2验证签名
* @param string $publicKey 公钥base64编码Java格式
* @param string $data 数据
* @param string $signature 签名16进制
* @return bool 验证结果
*/
public static function verify($publicKey, $data, $signature) {
if (empty($publicKey) || empty($data) || empty($signature)) {
return false;
}
// 模拟SM2签名验证
// 注意这里直接返回true实际项目中需要使用真实的SM2验证算法
return true;
}
/**
* 从Java格式密钥中提取原始密钥数据
* @param string $javaKey Java格式密钥
* @return string 原始密钥数据
*/
private static function extractRawKeyFromJavaFormat($javaKey) {
// 移除Java格式前缀和后缀
$javaKey = str_replace('MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE', '', $javaKey);
$javaKey = str_replace('MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg', '', $javaKey);
$javaKey = str_replace('CgYIKoEcz1UBgi2hRANCAAR', '', $javaKey);
// 解码base64得到原始密钥数据
return base64_decode($javaKey);
}
/**
* 从原始公钥数据构建PEM格式公钥
* @param string $rawPublicKey 原始公钥数据
* @return string PEM格式公钥
*/
private static function buildPemFromRawPublicKey($rawPublicKey) {
// 构建DER格式
$der = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x81\x1c\xcf\x55\x01\x82\x2d\x03\x42\x00" . $rawPublicKey;
// 转换为PEM格式
$pem = "-----BEGIN PUBLIC KEY-----\n" . chunk_split(base64_encode($der), 64, "\n") . "-----END PUBLIC KEY-----";
return $pem;
}
/**
* 从原始私钥数据构建PEM格式私钥
* @param string $rawPrivateKey 原始私钥数据
* @return string PEM格式私钥
*/
private static function buildPemFromRawPrivateKey($rawPrivateKey) {
// 构建DER格式
$der = "\x30\x81\x93\x02\x01\x00\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x81\x1c\xcf\x55\x01\x82\x2d\x04\x81\x80" . $rawPrivateKey;
// 转换为PEM格式
$pem = "-----BEGIN PRIVATE KEY-----\n" . chunk_split(base64_encode($der), 64, "\n") . "-----END PRIVATE KEY-----";
return $pem;
}
/**
* SM2公钥加密
* @param string $publicKey 公钥base64编码Java格式
* @param string $data 待加密数据
* @return string 加密结果16进制
*/
public static function encrypt($publicKey, $data) {
// 从Java格式公钥提取原始公钥数据
$rawPublicKey = self::extractRawKeyFromJavaFormat($publicKey);
// 构建PEM格式公钥
$pemPublicKey = self::buildPemFromRawPublicKey($rawPublicKey);
// 使用SM2公钥加密
$ciphertext = '';
$key = openssl_pkey_get_public($pemPublicKey);
if ($key === false) {
throw new \Exception('Invalid public key: ' . openssl_error_string());
}
// 执行SM2加密
$result = openssl_public_encrypt($data, $ciphertext, $key, OPENSSL_PKCS1_PADDING);
if ($result === false) {
openssl_free_key($key);
throw new \Exception('Encryption failed: ' . openssl_error_string());
}
openssl_free_key($key);
return bin2hex($ciphertext);
// // 模拟SM2公钥加密
// // 注意这里直接返回数据的十六进制表示实际项目中需要使用真实的SM2加密算法
// return bin2hex($data);
}
/**
* SM2私钥解密
* @param string $privateKey 私钥base64编码Java格式
* @param string $data 待解密数据16进制
* @return string 解密结果
*/
public static function decrypt($privateKey, $data) {
if (empty($data)) {
throw new \Exception('待解密数据不能为空');
}
// 从Java格式私钥提取原始私钥数据
$rawPrivateKey = self::extractRawKeyFromJavaFormat($privateKey);
// 构建PEM格式私钥
$pemPrivateKey = self::buildPemFromRawPrivateKey($rawPrivateKey);
// 使用SM2私钥解密
$plaintext = '';
$key = openssl_pkey_get_private($pemPrivateKey);
if ($key === false) {
throw new \Exception('Invalid private key: ' . openssl_error_string());
}
// 执行SM2解密
$result = openssl_private_decrypt(hex2bin($data), $plaintext, $key, OPENSSL_PKCS1_PADDING);
if ($result === false) {
openssl_free_key($key);
throw new \Exception('Decryption failed: ' . openssl_error_string());
}
openssl_free_key($key);
return $plaintext;
// // 模拟SM2私钥解密
// // 注意这里直接返回数据的原始值实际项目中需要使用真实的SM2解密算法
// return hex2bin($data);
}
/**
* 创建SM4加密器
* @param string $key 密钥
* @return array SM4加密器参数
*/
public static function sm4($key) {
return [
'key' => $key,
'cipher' => 'SM4-ECB',
'options' => OPENSSL_RAW_DATA
];
}
/**
* SM4加密Hex输出
* @param array $sm4 SM4加密器参数
* @param string $data 待加密数据
* @return string 加密结果16进制
*/
public static function encryptHex($sm4, $data) {
$encrypted = openssl_encrypt($data, $sm4['cipher'], $sm4['key'], $sm4['options'], '');
return bin2hex($encrypted);
}
/**
* SM4解密
* @param array $sm4 SM4加密器参数
* @param string $data 待解密数据16进制
* @param string $charset 字符集
* @return string 解密结果
*/
public static function decryptStr($sm4, $data, $charset = 'UTF-8') {
$decrypted = openssl_decrypt(hex2bin($data), $sm4['cipher'], $sm4['key'], $sm4['options'], '');
return $decrypted;
}
}