<?php
namespace app\home\controller;
use app\common\logic\UserAddressLogic;
use app\common\logic\GoodsActivityLogic;
use app\common\logic\CouponLogic;
use app\common\logic\IntegralLogic;
use app\common\logic\CartLogic;
use app\common\logic\OrderLogic;
use app\common\logic\PickupLogic;
use app\common\model\SpecGoodsPrice;
use app\common\model\Goods;
use think\Db;
header("Content-type:text/html;charset=utf-8");
//e签宝
class Eqb extends Base {
private $redirectUrl =''; //签属结束后跳转页
private $notifyUrl =''; //签属回调页
private $eSignAppId =''; //app id
private $eSignAppSecret=''; // app key
private $eSignHost ='https://smlopenapi.esign.cn'; //模拟环境
private $eSignUpload ='https://esignoss.esign.cn'; //文件流
// private $eSignUpload ='https://oss.esign.cn'; //模拟环境
// private $eSignHost ='https://openapi.esign.cn'; //正式环境
/**
* 初始化函数
*/
public function _initialize()
{
}
//消息回调通知
public function notifyurl(){
$data = file_get_contents('php://input');
file_put_contents('eqb.txt',$data,FILE_APPEND);//追加写入消息日志
$json = json_decode($data,true);
if($json['action']=='SIGN_MISSON_COMPLETE' && $json['signResult']==2){
//签署完成
$mobile = $json['operator']['psnAccount']['accountMobile'];
$user = M('users')->where(['mobile'=>$mobile])->save(['eqb_status'=>1]);
}
// $json = [
// "action" => "SIGN_MISSON_COMPLETE",
// "timestamp" => 1718267179875,
// "signFlowId" => "46b0609529ad458e8a3eec361e3f87f7",
// "customBizNum" => "1718267148",
// "signOrder" => 1,
// "operateTime" => 1718267179000,
// "signResult" => 2,
// "resultDescription" => "签署完成",
// "operator" => [
// "psnId" => "030abcd9221f478e8446600054ed1772",
// "psnAccount" => [
// "accountMobile" => "15241508811"
// ]
// ]
// ];
// echo 12;die;
}
//印章回调通知
public function notifyyinzhang(){
$data = file_get_contents('php://input');
file_put_contents('eqbyinzhang.txt',$data,FILE_APPEND);//追加写入消息日志
// echo 12;die;
}
//展示页面测试
public function show(){
return $this->fetch('index/eqb');
}
//上传本地文件
public function upload($filePath='',$fileName=''){
$url = '/v3/files/file-upload-url';
$host = $this->eSignHost.'/v3/files/file-upload-url';
// $filePath = "./esign/平台用户合作协议(青抖云).pdf";
// 文件Content-MD5值 4wobwYcP/xHBzdaIx4hiuQ==
$fileContentMD5 = $this->getFileContentMD5($filePath);
// echo $fileContentMD5;die;
$content_type = "application/pdf";
$data = [
'contentMd5'=>$fileContentMD5,
'contentType'=>$content_type,
'convertToPDF'=>false,
'fileName'=>$fileName,
'fileSize'=>filesize($filePath)
];
$json = json_encode($data,JSON_UNESCAPED_UNICODE);
$headers = $this->buildSignedHeaders($this->eSignAppId,$this->eSignAppSecret,'POST', $json, 'application/json; charset=UTF-8', $url);
$res = $this->sendPost($host,$json,$headers);
$result = json_decode($res,true);
if($result['code']==0){
$fileUploadUrl = $result['data']['fileUploadUrl'];//文件上传地址,链接有效期60分钟
$fileId = $result['data']['fileId'];//文件id 3d2c5d7691fc4c8081d0e63cbba8adb9
$headers_put = [
'Content-MD5:'.$fileContentMD5,
'Content-Type:'.$content_type,
];
$content_put = file_get_contents($filePath);//文件字节流
$put = $this->sendPut($fileUploadUrl,$content_put,$headers_put);
$result_put = json_decode($put,true);
if($result_put['errCode']==0){
// echo $fileId.'成功';
$chom = $this->file_status($fileId);
if($chom['code'] == 0){
return ['code'=>0,'msg'=>'文件ok','data'=>$fileId];
}else{
return ['code'=>1,'msg'=>'文件状态不满足'];
}
// ll($chom);
// return $chom;
}else{
// echo 'GG';
return ['code'=>1,'msg'=>'文件流上传E签宝失败'];
}
// ll($headers_put);
// ll($fileId);
// ll($put);
}else{
return ['code'=>1,'msg'=>'本地文件上传E签宝失败'];
// echo '文件上传error';
}
// ll($result);
}
//查询文件状态
public function file_status($fileId){
// $fileId = 'a7753f49de694528af12d391fee1c59f';
$url = '/v3/files/'.$fileId;
$host = $this->eSignHost.'/v3/files/'.$fileId;
$content_type = "application/json; charset=UTF-8";
// $data = [
// 'fileId'=>$fileId,
// ];
// $json = json_encode($data,JSON_UNESCAPED_UNICODE);
$headers = $this->buildSignedHeaders($this->eSignAppId,$this->eSignAppSecret,'GET', $fileId, 'application/json; charset=UTF-8', $url);
// ll($headers);die;
$get = $this->sendGet($host,$headers);
if($get['code'] == 0){
if($get['data']['fileStatus'] == 2 || $get['data']['fileStatus']==5){
return ['code'=>0,'msg'=>'可以使用'];
}else{
return ['code'=>1,'msg'=>'查询文件状态错误'];
}
}else{
return ['code'=>1,'msg'=>'查询状态请求失败'];
}
// ll($get);
}
//创建签属
public function create(){
$arr = I('post.');
// $signFlowExpireTime = round(microtime(true) * 1000 + 86400);//流程过期时间
$user_id = input('user_id',6085);
$user = M('users')->field('username,mobile,eqb_link,eqb_status')->where(['user_id'=>$user_id])->find();
if(empty($user)){
$this->ajaxReturn(['code'=>1,'msg'=>'登录失效']);
}
//判断是否有链接
if(!empty($user['eqb_link']) && $user['eqb_status']==0){
//未签约用户中途退出 重新拉起签署链接
$this->ajaxReturn(['code'=>0,'msg'=>'可以使用','data'=>['url'=>$user['eqb_link']]]);
}
$mobile = $user['mobile'];
$username = $user['username'];
//查询模板页码数
$fileId = M('config')->where(['name'=>'eqb_fileid','inc_type'=>'eqb'])->getField('value');
$fileName = M('config')->where(['name'=>'eqb_filename','inc_type'=>'eqb'])->getField('value');
if(empty($fileId) || empty($fileName)){
$this->ajaxReturn(['code'=>1,'msg'=>'模板合同不存在,请联系管理员']);
}
$page = M('config')->where(['name'=>'eqb_page','inc_type'=>'eqb'])->getField('value');
$positionx = M('config')->where(['name'=>'eqb_positionx','inc_type'=>'eqb'])->getField('value');
$positiony = M('config')->where(['name'=>'eqb_positiony','inc_type'=>'eqb'])->getField('value');
// ll($fileName);
// ll($fileId);die;
$url = '/v3/sign-flow/create-by-file';
$host = $this->eSignHost.$url;
$content_type = "application/json; charset=UTF-8";
$data = [
"docs" => [
"0" => [
"fileId" => $fileId,
"fileName" => $fileName
]
],
"signFlowConfig" => [
"signFlowTitle" => "平台用户合作协议",
"autoFinish" => true,
"notifyUrl" => $this->notifyUrl,
"redirectConfig" => [
"redirectUrl" => $this->redirectUrl,
]
],
"signers" => [
"0" => [
"signConfig" => [
"signOrder" => 1
],
"noticeConfig" => [
"noticeTypes" => ""
],
"signerType" => 0,
"psnSignerInfo" => [
"psnAccount" => $mobile,
"psnInfo" => [
"psnName" => $username
]
],
"signFields" => [
"0" => [
"customBizNum" => time(),
"fileId" => $fileId,//20240612截至123
"normalSignFieldConfig" => [
"signFieldStyle" => 1,
"signFieldPosition" => [
"positionPage" =>$page,
"positionX" => $positionx,
"positionY" => $positiony
]
]
]
]
],
// "1" => [
// "signConfig" => [
// "signOrder" => 2
// ],
// "signerType" => 1,
// "signFields" => [
// "0" => [
// "customBizNum" => time(),
// "fileId" => $fileId,
// "normalSignFieldConfig" => [
// "autoSign" =>false ,
// "signFieldStyle" => 1,
// "signFieldPosition" => [
// "positionPage" => "1",
// "positionX" => 458,
// "positionY" => 200
// ]
// ]
// ]
// ]
// ]
]
];
$json = json_encode($data,JSON_UNESCAPED_UNICODE);
// ll($data);die;
$headers = $this->buildSignedHeaders($this->eSignAppId,$this->eSignAppSecret,'POST', $json, 'application/json; charset=UTF-8', $url);
// ll($json);
// ll($headers);
$post = $this->sendPost($host,$json,$headers);
$res = json_decode($post,true);
if($res['code'] == 0){
$signFlowId = $res['data']['signFlowId'];//签属id
//调用获取签署链接
$geturl = $this->get_url($signFlowId,$mobile);
if($geturl['code']==0){
//客户存储
$eqb_link = $geturl['data']['url'];//签署跳转链接
$user_change = M('users')->where(['user_id'=>$user_id])->save(['eqb_flowid'=>$signFlowId,'eqb_link'=>$eqb_link]);
if(!$user_change){
$this->ajaxReturn(['code'=>1,'msg'=>'用户签约流程ID存储失败']);
}
$this->ajaxReturn(['code'=>0,'msg'=>'可以使用','data'=>$geturl['data']]);
}else{
$this->ajaxReturn(['code'=>1,'msg'=>$geturl['msg']]);
}
}else{
$this->ajaxReturn(['code'=>1,'msg'=>'创建签署请求失败']);
}
//res['data'] = {"signFlowId":"83d4e4ae063046a08b3ba5950a224560"}}"
}
//获取签签署页链接
public function get_url($signFlowId='',$mobile=''){
$url = '/v3/sign-flow/'.$signFlowId.'/sign-url';
$host = $this->eSignHost.$url;
$data = [
"clientType" => "ALL",
"needLogin" => false,
"operator" => [
"psnAccount" => $mobile
],
"redirectConfig"=>[
"redirectUrl"=>$this->redirectUrl,
"redirectDelayTime"=>0,
],
"urlType" => 2
];
$json = json_encode($data,JSON_UNESCAPED_UNICODE);
// ll($data);die;
$headers = $this->buildSignedHeaders($this->eSignAppId,$this->eSignAppSecret,'POST', $json, 'application/json; charset=UTF-8', $url);
// ll($json);
// ll($headers);
$post = $this->sendPost($host,$json,$headers);
$res = json_decode($post,true);
// ll($res);
if($res['code'] == 0){
return ['code'=>0,'data'=>$res['data']];
}else{
return ['code'=>1,'msg'=>'签署连接请求失败'];
}
}
public function getFileContentMD5($filePath){
//获取文件MD5的128位二进制数组
$md5Bytes = md5_file($filePath,true);
//计算文件的Content-MD5
$contentMD5 = base64_encode($md5Bytes);
return $contentMD5;
}
public function getContentMd5($bodyData){
//计算Body体的Content-MD5
$md5Bytes = md5($bodyData,true);
$contentMD5 = base64_encode($md5Bytes);
return $contentMD5;
}
//创建签名
public function getSignature( $method, $content_md5, $content_type, $uri, $app_secret){
$string = "$method\n*/*\n$content_md5\n$content_type\n\n$uri";
return base64_encode(hash_hmac('sha256', $string, $app_secret, true));
}
//创建请求头
public function buildSignedHeaders($app_id, $app_secret, $method, $body, $content_type, $uri){
$contentMd5 = '';
if (in_array($method, ['GET', 'DELETE'])) {
$content_type = '';
} else {
$contentMd5 = $this->getContentMd5($body);
}
$header = [
'Accept' => '*/*',
'Content-MD5' => $contentMd5,
'Content-Type' => $content_type,
'X-Tsign-Open-App-Id' => $app_id,
'X-Tsign-Open-Auth-Mode' => 'Signature',
'X-Tsign-Open-Ca-Signature' => $this->getSignature($method, $contentMd5, $content_type, $uri, $app_secret),
'X-Tsign-Open-Ca-Timestamp' => round(microtime(true) * 1000),
];
$headers = [];
foreach ($header as $k => $v) {
array_push($headers,$k.':'.$v);
}
return $headers;
}
// public function getMillisecond(): float {
// [$t1, $t2] = explode(' ', microtime());
// return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
// }
public function sendGet($url,$headers=[]){
//用curl传参
$ch = curl_init();
if (count($headers) >= 1) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
//关闭ssl验证
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch,CURLOPT_HEADER, 0);
$output = curl_exec($ch);
curl_close($ch);
return json_decode($output, true);
}
//curl请求
public function sendPost($url,$data = null,$headers = array()){
$curl = curl_init();
// $headers = [
// 'Accept: application/json',
// 'Content-Type: application/json',
// 'User-Agent: My User Agent String'
// ];
if (count($headers) >= 1) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); // 跳过证书检查
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); // 从证书中检查SSL加密算法是否存在
if (!empty($data)) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
public function sendPut($url,$data,$header){
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url); //定义请求地址
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); //
curl_setopt($curl, CURLOPT_HEADER,0); //定义是否显示状态头 1:显示 ; 0:不显示
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);//定义header
curl_setopt($curl, CURLOPT_RETURNTRANSFER,1);//定义是否直接输出返回流
curl_setopt($curl, CURLOPT_POSTFIELDS, $data); //定义提交的数据
$tmpInfo = curl_exec($curl); // 执行操作
if (curl_errno($curl)) {
echo 'Errno'.curl_error($curl);
}
curl_close($curl); // 关键CURL会话
return $tmpInfo; // 返回数据
}
}
一把梭直接控制器拼接请求头快速调用,回调和模板上传需要自己写逻辑套用路径即可,印章定位需要根据平台工具操作获取签章位置-e签宝-电子签名|电子合同|专业电子签约云平台