作者 何书鹏
1 个管道 的构建 通过 耗费 16 秒

隐私保护通话测试

... ... @@ -95,4 +95,22 @@ if(!function_exists('range_time')){
return false;
}
}
}
if(!function_exists('build_wsse_header')){
/**
* 构建X-WSSE值
*
* @param string $appKey
* @param string $appSecret
* @return string
*/
function build_wsse_header($appKey, $appSecret) {
date_default_timezone_set("UTC");
$Created = date('Y-m-d\TH:i:s\Z'); //Created
$nonce = uniqid(); //Nonce
$base64 = base64_encode(hash('sha256', ($nonce . $Created . $appSecret), TRUE)); //PasswordDigest
return sprintf("UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"", $appKey, $base64, $nonce, $Created);
}
}
\ No newline at end of file
... ...
... ... @@ -9,6 +9,7 @@ use app\api\model\UserLicensePlate;
use app\api\model\OrderGrab;
use app\api\model\User;
use app\api\model\Message;
use app\api\model\PrivateNumber as PrivateNumberModel;
use app\common\controller\Wechat;
use think\Db;
... ... @@ -60,6 +61,7 @@ class Order extends Api
$post['deposit'] <= 0 && $this->error('最高可接受停车费用不能小于0元');
$user = User::get($this->auth->id);
empty($user['license_plate']) && $this->error('请先在我的资料中补全认证信息','暂未填写认证信息',3);
empty($user['mobile']) && $this->error('请先在我的资料中补全手机号','暂未填写手机号',3);
$this->model->allowField(true)->save(array_merge([
'user_id' => $this->auth->id,
'order_sn' => get_order_sn(),
... ... @@ -439,6 +441,16 @@ class Order extends Api
$templateid = config('tmplmsg.template')['refund_success'];
$url = config('tmplmsg.vue_url').'/wallet';
(new Wechat)->tmplmsg($openid,$send_data,$templateid,$url);
// 解绑隐私通话
$has_number = PrivateNumberModel::get(['order_id'=>$order['id']]);
if($has_number){
$count = PrivateNumberModel::where('subscription_id',$has_number['subscription_id'])->count();
if($count > 1){
$has_number->delete();
}else{
(new PrivateNumber)->unbind($has_number['subscription_id']);
}
}
return true;
}
... ... @@ -525,6 +537,30 @@ class Order extends Api
$templateid1 = config('tmplmsg.template')['order_change'];
$url1 = config('tmplmsg.vue_url').'/indent?id='.$order['id'].'&type=2';
(new Wechat)->tmplmsg($openid1,$send_data1,$templateid1,$url1);
// 绑定隐私通话
$mobile_a = User::where('id',$order['user_id'])->value('mobile');
$mobile_b = User::where('id',$grab['user_id'])->value('mobile');
$find = PrivateNumberModel::where(function($query)use($mobile_a,$mobile_b){
$query->where('mobile_a','+86'.$mobile_a)->where('mobile_b','+86'.$mobile_b);
})->whereOr(function($query)use($mobile_a,$mobile_b){
$query->where('mobile_a','+86'.$mobile_b)->where('mobile_b','+86'.$mobile_a);
})->find();
$privateNumberController = new PrivateNumber;
if($find){
if($privateNumberController->search($find['subscriptionId'])){
Db::name('private_number')->insert([
'order_id' => $order['id'],
'mobile_a' => $find['mobile_a'],
'mobile_b' => $find['mobile_b'],
'mobile_x' => $find['mobile_x'],
'subscription_id'=> $find['subscription_id'],
]);
}else{
$privateNumberController->bind($mobile_a,$mobile_b,$order['id']);
}
}else{
$privateNumberController->bind($mobile_a,$mobile_b,$order['id']);
}
return true;
}
... ... @@ -603,6 +639,16 @@ class Order extends Api
$templateid = config('tmplmsg.template')['order_complete'];
$url = config('tmplmsg.vue_url').'/indenta?id='.$grab['id'].'&type=4';
(new Wechat)->tmplmsg($openid,$send_data,$templateid,$url);
// 解绑隐私通话
$has_number = PrivateNumberModel::get(['order_id'=>$order['id']]);
if($has_number){
$count = PrivateNumberModel::where('subscription_id',$has_number['subscription_id'])->count();
if($count > 1){
$has_number->delete();
}else{
(new PrivateNumber)->unbind($has_number['subscription_id']);
}
}
return true;
}
... ...
... ... @@ -161,6 +161,7 @@ class OrderGrab extends Api
$user = $this->auth->getUser();
$user['score'] <= -20 && $this->error('您的积分小于等于-20您无法抢单','积分过低',2);
empty($user['market_ids']) && $this->error('请先在我的资料中补全认证信息','暂未填写认证信息',3);
empty($user['mobile']) && $this->error('请先在我的资料中补全手机号','暂未填写手机号',3);
$grab_price > $order['deposit'] && $this->error('出价不能大于'.$order['deposit'].'元');
Db::startTrans();
try{
... ... @@ -177,7 +178,7 @@ class OrderGrab extends Api
'type' => '2',
'order_status' => '1',
]);
// 只有人抢单直接给他
// 只有人抢单直接给他
$new_order = Order::get($order_id);
(new \app\api\controller\Order)->dealAction($new_order);
Db::commit();
... ...
<?php
namespace app\api\controller;
use app\common\controller\Api;
use think\Db;
/**
* @ApiInternal
* 隐私保护通话接口
*/
class PrivateNumber extends Api
{
//如果$noNeedLogin为空表示所有接口都需要登录才能请求
//如果$noNeedRight为空表示所有接口都需要验证权限才能请求
//如果接口已经设置无需登录,那也就无需鉴权了
//
// 无需登录的接口,*表示全部
protected $noNeedLogin = ['bind', 'search', 'unbind'];
// 无需鉴权的接口,*表示全部
protected $noNeedRight = ['*'];
/**
* 测试方法
*
* @ApiTitle (测试名称)
* @ApiSummary (测试描述信息)
* @ApiMethod (POST)
* @ApiRoute (/api/demo/test/id/{id}/name/{name})
* @ApiHeaders (name=token, type=string, required=true, description="请求的Token")
* @ApiParams (name="id", type="integer", required=true, description="会员ID")
* @ApiParams (name="name", type="string", required=true, description="用户名")
* @ApiParams (name="data", type="object", sample="{'user_id':'int','user_name':'string','profile':{'email':'string','age':'integer'}}", description="扩展数据")
* @ApiReturnParams (name="code", type="integer", required=true, sample="0")
* @ApiReturnParams (name="msg", type="string", required=true, sample="返回成功")
* @ApiReturnParams (name="data", type="object", sample="{'user_id':'int','user_name':'string','profile':{'email':'string','age':'integer'}}", description="扩展数据返回")
* @ApiReturn ({
'code':'1',
'msg':'返回成功'
})
*/
public function bind($mobile_a = '15133120361',$mobile_b = '15620696576',$order_id = 0)
{
// 必填,请参考"开发准备"获取如下数据,替换为实际值
$realUrl = config('privatenumber.real_url'); // APP接入地址+接口访问URI
$APP_KEY = config('privatenumber.app_key'); // APP_Key
$APP_SECRET = config('privatenumber.app_secret'); // APP_Secret
// $relationNum = '+8617010000001'; // X号码(隐私号码)
$callerNum = '+86'.$mobile_a; // A号码
$calleeNum = '+86'.$mobile_b; // B号码
/*
* 选填,各参数要求请参考"AXB模式绑定接口"
*/
$areaCode = '021'; // 需要绑定的X号码对应的城市码
// $callDirection = 0; // 允许呼叫的方向
// $duration = 86400; // 绑定关系保持时间,单位为秒。到期后会被系统自动解除绑定关系
// $recordFlag = 'false'; // 是否需要针对该绑定关系产生的所有通话录音
// $recordHintTone = 'recordHintTone.wav'; // 设置录音提示音
// $maxDuration = 60; // 设置允许单次通话进行的最长时间,单位为分钟。通话时间从接通被叫的时刻开始计算
// $lastMinVoice = 'lastMinVoice.wav'; // 设置通话剩余最后一分钟时的提示音
// $privateSms = 'true'; // 设置该绑定关系是否支持短信功能
// $callerHintTone = 'callerHintTone.wav'; // 设置A拨打X号码时的通话前等待音
// $calleeHintTone = 'calleeHintTone.wav'; // 设置B拨打X号码时的通话前等待音
// $preVoice = [
// 'callerHintTone' => $callerHintTone,
// 'calleeHintTone' => $calleeHintTone
// ];
// 请求Headers
$headers = [
'Accept: application/json',
'Content-Type: application/json;charset=UTF-8',
'Authorization: WSSE realm="SDP",profile="UsernameToken",type="Appkey"',
'X-WSSE: ' . build_wsse_header($APP_KEY, $APP_SECRET)
];
// 请求Body,可按需删除选填参数
$data = json_encode([
// 'relationNum' => $relationNum,
'areaCode' => $areaCode,
'callerNum' => $callerNum,
'calleeNum' => $calleeNum,
// 'callDirection' => $callDirection,
// 'duration' => $duration,
// 'recordFlag' => $recordFlag,
// 'recordHintTone' => $recordHintTone,
// 'maxDuration' => $maxDuration,
// 'lastMinVoice' => $lastMinVoice,
// 'privateSms' => $privateSms,
// 'preVoice' => $preVoice
]);
$context_options = [
'http' => [
'method' => 'POST', // 请求方法为POST
'header' => $headers,
'content' => $data,
'ignore_errors' => true // 获取错误码,方便调测
],
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false
] // 为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
];
try {
$file=fopen('bind_data.txt', 'a'); //打开文件
// print_r($data . PHP_EOL); // 打印请求数据
fwrite($file, '绑定请求数据:' . $data . PHP_EOL); //绑定请求参数记录到本地文件,方便定位问题
$response = file_get_contents($realUrl, false, stream_context_create($context_options)); // 发送请求
// print_r($response . PHP_EOL); // 打印响应结果
fwrite($file, '绑定结果:' . $response . PHP_EOL); //绑定ID很重要,请记录到本地文件,方便后续修改绑定关系及解绑
$res = json_decode($response,true);
if($res['resultcode'] != '0'){
$this->error($res['resultdesc']);
}
Db::name('private_number')->insert([
'order_id' => $order_id,
'mobile_a' => $callerNum,
'mobile_b' => $calleeNum,
'mobile_x' => $res['relationNum'],
'subscription_id'=> $res['subscriptionId'],
]);
echo $res['subscriptionId'];
} catch (Exception $e) {
$this->error($e->getMessage());
} finally {
fclose($file); //关闭文件
}
}
/**
* 查询接口
*/
public function search($subscriptionId = '',$relationNum = '')
{
// 必填,请参考"开发准备"获取如下数据,替换为实际值
$realUrl = config('privatenumber.real_url'); // APP接入地址+接口访问URI
$APP_KEY = config('privatenumber.app_key'); // APP_Key
$APP_SECRET = config('privatenumber.app_secret'); // APP_Secret
/*
* 选填,各参数要求请参考"AXB模式绑定信息查询接口"
* subscriptionId和relationNum为二选一关系,两者都携带时以subscriptionId为准
*/
// $subscriptionId = '0167ecc9-bfb6-4eec-b671-a7dab2ba78cf'; // 指定"AXB模式绑定接口"返回的绑定ID进行查询
// $relationNum = '+8617010000001'; // 指定X号码(隐私号码)进行查询
// $pageIndex = 1; //查询的分页索引,从1开始编号
// $pageSize = 20; //查询的分页大小,即每次查询返回多少条数据
// 请求Headers
$headers = [
'Accept: application/json',
'Content-Type: application/json;charset=UTF-8',
'Authorization: WSSE realm="SDP",profile="UsernameToken",type="Appkey"',
'X-WSSE: ' . build_wsse_header($APP_KEY, $APP_SECRET)
];
// 请求URL参数
$data = http_build_query([
'subscriptionId' => $subscriptionId,
'relationNum' => $relationNum
// 'pageIndex' => $pageIndex,
// 'pageSize' => $pageSize
]);
// 完整请求地址
$fullUrl = $realUrl . '?' . $data;
$context_options = [
'http' => [
'method' => 'GET', // 请求方法为GET
'header' => $headers,
'ignore_errors' => true // 获取错误码,方便调测
],
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false
] // 为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
];
try {
$file=fopen('bind_data.txt', 'a'); //打开文件
$response = file_get_contents($fullUrl, false, stream_context_create($context_options)); // 发送请求
// print_r($response . PHP_EOL); // 打印响应结果
fwrite($file, '绑定查询结果:' . $response . PHP_EOL); //查询结果,记录到本地文件
$res = json_decode($response,true);
if($res['resultcode'] != '0'){
if($res['resultcode'] == '1012007'){
Db::name('private_number')->where('subscription_id',$subscriptionId)->delete();
return false;
}
$this->error($res['resultdesc']);
}
return true;
} catch (Exception $e) {
$this->error($e->getMessage());
} finally {
fclose($file); //关闭文件
}
}
/**
* 解绑接口
*/
public function unbind($subscriptionId = '',$relationNum = '')
{
// 必填,请参考"开发准备"获取如下数据,替换为实际值
$realUrl = config('privatenumber.real_url'); // APP接入地址+接口访问URI
$APP_KEY = config('privatenumber.app_key'); // APP_Key
$APP_SECRET = config('privatenumber.app_secret'); // APP_Secret
/*
* 选填,各参数要求请参考"AXB模式解绑接口"
* subscriptionId和relationNum为二选一关系,两者都携带时以subscriptionId为准
*/
// $subscriptionId = '0167ecc9-bfb6-4eec-b671-a7dab2ba78cf';
// $relationNum = '+8617010000001';
// 请求Headers
$headers = [
'Accept: application/json',
'Content-Type: application/json;charset=UTF-8',
'Authorization: WSSE realm="SDP",profile="UsernameToken",type="Appkey"',
'X-WSSE: ' . build_wsse_header($APP_KEY, $APP_SECRET)
];
// 请求URL参数
$data = http_build_query([
'subscriptionId' => $subscriptionId,
'relationNum' => $relationNum
]);
// 完整请求地址
$fullUrl = $realUrl . '?' . $data;
$context_options = [
'http' => [
'method' => 'DELETE', // 请求方法为DELETE
'header' => $headers,
'ignore_errors' => true // 获取错误码,方便调测
],
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false
] // 为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
];
try {
// print_r($data . PHP_EOL); // 打印请求数据
$response = file_get_contents($fullUrl, false, stream_context_create($context_options)); // 发送请求
// print_r($response . PHP_EOL); // 打印响应结果
$res = json_decode($response,true);
if($res['resultcode'] != '0') {
$this->error($res['resultdesc']);
}
Db::name('private_number')->where('subscription_id',$subscriptionId)->delete();
} catch (Exception $e) {
$this->error($e->getMessage());
}
$this->success('解绑成功');
}
}
... ...
... ... @@ -18,7 +18,8 @@ class Order extends Model
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [
'grab_countdown'
'grab_countdown',
'private_number'
];
// 所有抢单
... ... @@ -45,4 +46,13 @@ class Order extends Model
'second' => $grab_countdown % 60
];
}
// 对方隐私号码
public function getPrivateNumberAttr($value,$data){
$private_number = PrivateNumber::where('order_id',$data['id'])->find();
if($private_number){
return $private_number['mobile_x'];
}
return '';
}
}
... ...
... ... @@ -18,7 +18,8 @@ class OrderGrab extends Model
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [
'pay_countdown'
'pay_countdown',
'private_number'
];
// 用户信息
... ... @@ -54,4 +55,13 @@ class OrderGrab extends Model
'second' => $pay_countdown % 60
];
}
// 对方隐私号码
public function getPrivateNumberAttr($value,$data){
$private_number = PrivateNumber::where('order_id',$data['id'])->find();
if($private_number){
return $private_number['mobile_x'];
}
return '';
}
}
... ...
<?php
namespace app\api\model;
use think\Model;
/**
* 隐私保护通话模型
*/
class PrivateNumber extends Model
{
// 表名
protected $name = 'private_number';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [];
}
... ...
<?php
// 小程序参数配置
return [
'real_url' => 'https://rtcpns.cn-north-1.myhuaweicloud.com:443/rest/caas/relationnumber/partners/v1.0',
'app_key' => 'pKPd55o3oywesF5Dba2t1xrx69Ed',
'app_secret' => 'KGKdiP5jnhT5dCMwSPiH96ogOqon',
];
\ No newline at end of file
... ...