<?php
ini_set('date.timezone','Asia/Shanghai');
ini_set("display_errors","On");
error_reporting(E_ALL);
define('FACESYNC_COMMAND_NONE', 0);
define('FACESYNC_REQUEST_FACE_IDS', 1);
define('FACESYNC_RESPONSE_FACE_IDS', 2);
define('FACESYNC_REQUEST_FACE_FEATURES', 3);
define('FACESYNC_RESPONSE_FACE_FEATURES', 4);
define('FACESYNC_REQUEST_FAREWELL', 5);
define('FACESYNC_RESPONSE_FAREWELL', 6);
/*
注意:
//模拟数据库存放三个人的数据
$test_feature_datas = array(
//张三
array(
//'u32Flag'=> 0,
'u32CheckSum'=> 0, //下面数据的校验码,主要用来判断特征结构是否被更新,可以不计算
'u64FaceId'=> 11111111, //faceid
'u64PersonId'=> 11111111, //personid
'u32UpdateTime'=> 0, //修改时间,主要用来判断特征结构是否被更新
//'u32FeatureCRC'=> 0, //特征校验码,可以不计算
'feature'=> '', //特征向量,填base64解码后的二进制数据,php的字符串直接可以存放二进制(不需要转十六进制字符)
'info'=> array(
//'u32Permission'=> 0, //权限
'szName'=> '张三', //姓名
'szNric'=> '123', //证件
'szCardNum'=> '123', //卡号
//'u32VaildDateBegin'=> 0, //有效期开始时间
//'u32VaildDateEnd'=> 0, //有效期结束时间
//'_reserv'=> '' //保留
)
),
//李四
array(
//'u32Flag'=> 0,
'u32CheckSum'=> 0, //下面数据的校验码,主要用来判断特征结构是否被更新,可以不计算
'u64FaceId'=> 22222222, //faceid
'u64PersonId'=> 22222222, //personid
'u32UpdateTime'=> 0, //修改时间,主要用来判断特征结构是否被更新
//'u32FeatureCRC'=> 0, //特征校验码,可以不计算
'feature'=> '', //特征向量,填base64解码后的二进制数据,php的字符串直接可以存放二进制(不需要转十六进制字符)
'info'=> array(
//'u32Permission'=> 0, //权限
'szName'=> '李四', //姓名
'szNric'=> '444', //证件
'szCardNum'=> '444', //卡号
//'u32VaildDateBegin'=> 0, //有效期开始时间
//'u32VaildDateEnd'=> 0, //有效期结束时间
//'_reserv'=> '' //保留
)
),
//陈五
array(
//'u32Flag'=> 0,
'u32CheckSum'=> 0, //下面数据的校验码,主要用来判断特征结构是否被更新,可以不计算
'u64FaceId'=> 33333333, //faceid
'u64PersonId'=> 33333333, //personid
'u32UpdateTime'=> 0, //修改时间,主要用来判断特征结构是否被更新
//'u32FeatureCRC'=> 0, //特征校验码,可以不计算
'feature'=> '', //特征向量,填base64解码后的二进制数据,php的字符串直接可以存放二进制(不需要转十六进制字符)
'info'=> array(
//'u32Permission'=> 0, //权限
'szName'=> '陈五', //姓名
'szNric'=> '555', //证件
'szCardNum'=> '555', //卡号
//'u32VaildDateBegin'=> 0, //有效期开始时间
//'u32VaildDateEnd'=> 0, //有效期结束时间
//'_reserv'=> '' //保留
)
)
);
class FaceSyncSDK
{
//CRC32校验算法 (要速度快请改查表法,网上没有,我不舍得开源)
function CRC32_Calc($buf, $offset, $length, $seed=0xFFFFFFFF)
{
$polynomial = 0x04c11db7;
$crc = $seed;
for ($i = $offset; $i < $offset + $length; $i++) {
$c = ord($buf[$i]);
$crc ^= ($c << 24);
for ($j = 0; $j < 8; $j++) {
if ($crc & 0x80000000) {
$crc = (($crc << 1) & 0xffffffff) ^ $polynomial;
} else {
$crc = ($crc << 1) & 0xffffffff;
}
}
}
return $crc;
}
//FACE_ID_SET_T 转 二进制
function pack_FACE_ID_SET_T($arr)
{
$bin = '';
$bin .= pack('Q', $arr['u64FaceId']);
$bin .= pack('L', $arr['u32UpdateTime']);
$bin .= pack('L', $arr['u32CheckSum']);
return $bin;
}
//二进制 转 FACE_ID_SET_T
function unpack_FACE_ID_SET_T($bin, $offset = 64)
{
$format = 'Qu64FaceId/Lu32UpdateTime/Lu32CheckSum';
return unpack($format, $bin, $offset);
}
//FACE_SYNC_CMD_T 转 二进制
function pack_FACE_SYNC_CMD_T($arr)
{
$bin = '';
$bin .= pack('L', isset($arr['checksum']) ? $arr['checksum'] : 0); //构造时可忽略参数
$bin .= pack('L', $arr['command']); //命令,必要的参数
$bin .= pack('L', isset($arr['groupnum']) ? $arr['groupnum'] : 0); //构造时可忽略参数
$bin .= pack('a20', isset($arr['serialnum']) ? $arr['serialnum'] : ''); //构造时可忽略参数
$bin .= pack('a24', isset($arr['_reserv']) ? $arr['_reserv'] : ''); //构造时可忽略参数
$bin .= pack('L', isset($arr['itemcount']) ? $arr['itemcount'] : 0); //构造时可忽略参数
$bin .= pack('L', isset($arr['itemsize']) ? $arr['itemsize'] : 0); //构造时可忽略参数
return $bin;
}
//二进制 转 FACE_SYNC_CMD_T
function unpack_FACE_SYNC_CMD_T($bin, $offset = 0)
{
$format = 'Lchecksum/Lcommand/Lgroupnum/a20serialnum/a24_reserv/Litemcount/Litemsize';
return unpack($format, $bin, $offset);
}
//FACE_FEATURE_T 转 二进制
function pack_FACE_FEATURE_T($arr)
{
$bin = '';
$bin .= pack('L', isset($arr['u32Flag']) ? $arr['u32Flag'] : 0);
$bin .= pack('L', isset($arr['u32CheckSum']) ? $arr['u32CheckSum'] : 0);
$bin .= pack('Q', $arr['u64FaceId']);
$bin .= pack('Q', $arr['u64PersonId']);
$bin .= pack('L', $arr['u32UpdateTime']);
$bin .= pack('L', isset($arr['u32FeatureCRC']) ? $arr['u32FeatureCRC'] : 0);
$bin .= pack('a2048', $arr['feature']);
//PERSON_INFO_T
$bin .= pack('L', isset($arr['info']['u32Permission']) ? $arr['info']['u32Permission'] : 0);
$bin .= pack('a32', isset($arr['info']['szName']) ? $arr['info']['szName'] : '');
$bin .= pack('a20', isset($arr['info']['szNric']) ? $arr['info']['szNric'] : '');
$bin .= pack('a24', isset($arr['info']['szCardNum']) ? $arr['info']['szCardNum'] : '');
$bin .= pack('L', isset($arr['info']['u32VaildDateBegin']) ? $arr['info']['u32VaildDateBegin'] : 0);
$bin .= pack('L', isset($arr['info']['u32VaildDateEnd']) ? $arr['info']['u32VaildDateEnd'] : 0);
$bin .= pack('a8', isset($arr['info']['_reserv']) ? $arr['info']['_reserv'] : '');
return $bin;
}
function parseCommand($inputstream)
{
$recvcmd = self::unpack_FACE_SYNC_CMD_T($inputstream, 0);
//printf("command = 0x%X, checksum = 0x%X\r\n", $recvcmd['command'], $recvcmd['checksum']);
$checksum = self::CRC32_Calc($inputstream, 4, strlen($inputstream)-4, 0xffffffff);
if($recvcmd['checksum'] != $checksum){
//printf("recv_checksum = 0x%X, calc_checksum = 0x%X\r\n", $recvcmd['checksum'], $checksum);
//if($_SERVER['REQUEST_METHOD'] != 'GET'){
return; //校验码错误返回
//}
}
if($recvcmd['command'] == FACESYNC_REQUEST_FACE_IDS){ //收到请求人脸列表命令
$checksum = 0xffffffff; //初始种子
$test_feature_datas = $GLOBALS['test_feature_datas']; //模拟读取数据库
$itemcount = count($test_feature_datas);
//生成协议头
$sendcmd = array(
'command'=> FACESYNC_RESPONSE_FACE_IDS, //回复人脸列表命令
'itemsize'=> 16, // FACE_ID_SET_T占16字节
'itemcount'=> $itemcount
);
$cmddata = self::pack_FACE_SYNC_CMD_T($sendcmd);
$checksum = self::CRC32_Calc($cmddata, 4, 60, $checksum); //计算协议头第4字节开始到末尾的校验码
//生成附加数据
$listdata = '';
foreach($test_feature_datas as $obj){
$face_id_set = self::pack_FACE_ID_SET_T($obj); //生成二进制列表项
$checksum = self::CRC32_Calc($face_id_set, 0, 16, $checksum); //累计校验码
$listdata .= $face_id_set; //二进制列表
}
$sendcmd['checksum'] = $checksum; //将最终数据包的校验码填入协议头
$cmddata = self::pack_FACE_SYNC_CMD_T($sendcmd); //重新封包协议头
//返回二进制流
header("Content-Type: application/octet-stream");
echo $cmddata; //发送协议头
echo $listdata; //发送附加数据
//flush();
}else if($recvcmd['command'] == FACESYNC_REQUEST_FACE_FEATURES){ //收到请求人脸特征命令
$checksum = 0xffffffff; //初始种子
$test_feature_datas = $GLOBALS['test_feature_datas']; //模拟读取数据库
$itemcount = $recvcmd['itemcount'];
$faceids = unpack("Q{$itemcount}", $inputstream, 64); //解包收到的N个人脸IDs //这里注意双引号
//生成协议头
$sendcmd = array(
'command'=> FACESYNC_RESPONSE_FACE_FEATURES, //回复人脸特征命令
'itemsize'=> 2176, // FACE_FEATURE_T占2176字节
'itemcount'=> $itemcount
);
$cmddata = self::pack_FACE_SYNC_CMD_T($sendcmd);
$checksum = self::CRC32_Calc($cmddata, 4, 60, $checksum); //计算协议头第4字节开始到末尾的校验码
//生成附加数据
$listdata = '';
$face_feature_item = '';
//查找客户端发来的faceid(s)对应的特征数据
$found = false;
foreach($faceids as $id){
foreach($test_feature_datas as $obj){
if($id == $obj['u64FaceId']){
$face_feature_item = self::pack_FACE_FEATURE_T($obj); //生成二进制列表项
$found = true;
break;
}
}
if(!$found){
$face_feature_item = pack('a2176', ''); //如果faceid刚好不存在则填充2176字节空白数据
}
$checksum = self::CRC32_Calc($face_feature_item, 0, 2176, $checksum); //累计校验码
$listdata .= $face_feature_item; //二进制列表
}
$sendcmd['checksum'] = $checksum; //将最终数据包的校验码填入协议头
$cmddata = self::pack_FACE_SYNC_CMD_T($sendcmd); //重新封包协议头
//返回二进制流
header("Content-Type: application/octet-stream");
echo $cmddata; //发送协议头
echo $listdata; //发送附加数据
//flush();
}
}
}
//######### Main() ###########
//phpinfo();
//print_r($test_feature_datas);
$inputstream = '';
if($_SERVER['REQUEST_METHOD'] == 'GET')
$inputstream = pack("L16", 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0); //GET测试返回人脸列表
else
$inputstream = file_get_contents('php://input'); //POST
$facesync = new FaceSyncSDK();
$facesync->parseCommand($inputstream);
?>
上面的文件是原始的数据文件,放到类型tp框架这种控制器是可以的,但是长住内存框架,我就搞不定了
看手册 https://www.workerman.net/doc/webman#/response 应该不难吧
应该是
多谢大佬,测试过了。,还是不行,返回的是一个流数据
public function hello(Request $request)
{
// 创建一个对象
$response = response();
}
多谢大佬,测试过了。,还是不行,返回的是一个流数据
@7810:数据流?是不是你没有转换进制
@4519: 用echo 是直接返回数据流回去的, 如果转换了设备不认,我用response不得,可能是我不知道怎么使用